zenith-foundation 0.1.0

Zenith 核心基础设施:统一错误类型、FrameToken 所有权令牌、FramePool、分层资源账本、恒定时间比较
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
//! 统一错误类型与错误处理规范
//!
//! 本模块定义 Zenith 框架的统一错误类型,
//! 所有错误都必须携带上下文信息,禁止返回裸错误。

use std::fmt;

/// 核心错误类型
#[derive(Debug, thiserror::Error)]
pub enum CoreError {
    /// 资源配额超限
    #[error("quota exceeded: limit={limit}, requested={requested}, resource={resource}")]
    QuotaExceeded {
        /// 资源类型
        resource: &'static str,
        /// 配额上限
        limit: u64,
        /// 请求数量
        requested: u64,
    },

    /// 资源未找到
    #[error("resource not found: id={id}, type={resource_type}")]
    ResourceNotFound {
        /// 资源ID
        id: u64,
        /// 资源类型
        resource_type: &'static str,
    },

    /// 资源已存在(重复创建)
    #[error("resource already exists: id={id}, type={resource_type}")]
    ResourceAlreadyExists {
        /// 资源ID
        id: u64,
        /// 资源类型
        resource_type: &'static str,
    },

    /// 资源已损坏
    #[error("resource poisoned: id={id}, reason={reason}")]
    ResourcePoisoned {
        /// 资源ID
        id: u64,
        /// 损坏原因
        reason: String,
    },

    /// 所有权错误
    #[error("ownership violation: expected={expected}, actual={actual}")]
    OwnershipViolation {
        /// 期望的所有者
        expected: &'static str,
        /// 实际的所有者
        actual: &'static str,
    },

    /// 地址范围无效
    #[error("invalid address range: addr={addr:x}, len={len}, max={max:x}")]
    InvalidAddressRange {
        /// 起始地址
        addr: u64,
        /// 长度
        len: u64,
        /// 最大地址
        max: u64,
    },

    /// 算术溢出
    #[error("arithmetic overflow: operation={op}, a={a}, b={b}")]
    ArithmeticOverflow {
        /// 操作符
        op: &'static str,
        /// 操作数a
        a: u64,
        /// 操作数b
        b: u64,
    },

    /// 状态冲突
    #[error("state conflict: current={current}, expected={expected}")]
    StateConflict {
        /// 当前状态
        current: String,
        /// 期望状态
        expected: String,
    },

    /// 无效配置
    #[error("invalid config: {field} — {reason}")]
    InvalidConfig {
        /// 配置字段名
        field: &'static str,
        /// 原因
        reason: &'static str,
    },

    /// 内部错误
    #[error("internal error: {0}")]
    Internal(String),

    /// 未知错误
    #[error("unknown error: {0}")]
    Unknown(String),
}

/// 核心结果类型
pub type CoreResult<T> = Result<T, CoreError>;

impl CoreError {
    /// 创建配额超限错误
    pub fn quota_exceeded(resource: &'static str, limit: u64, requested: u64) -> Self {
        CoreError::QuotaExceeded {
            resource,
            limit,
            requested,
        }
    }

    /// 创建资源未找到错误
    pub fn resource_not_found(id: u64, resource_type: &'static str) -> Self {
        CoreError::ResourceNotFound { id, resource_type }
    }

    /// 创建资源已存在错误
    pub fn resource_already_exists(id: u64, resource_type: &'static str) -> Self {
        CoreError::ResourceAlreadyExists {
            id,
            resource_type,
        }
    }

    /// 创建资源损坏错误
    pub fn resource_poisoned(id: u64, reason: impl Into<String>) -> Self {
        CoreError::ResourcePoisoned {
            id,
            reason: reason.into(),
        }
    }

    /// 创建所有权违规错误
    pub fn ownership_violation(expected: &'static str, actual: &'static str) -> Self {
        CoreError::OwnershipViolation { expected, actual }
    }

    /// 创建地址范围无效错误
    pub fn invalid_address_range(addr: u64, len: u64, max: u64) -> Self {
        CoreError::InvalidAddressRange { addr, len, max }
    }

    /// 创建算术溢出错误
    pub fn arithmetic_overflow(op: &'static str, a: u64, b: u64) -> Self {
        CoreError::ArithmeticOverflow { op, a, b }
    }

    /// 创建状态冲突错误
    pub fn state_conflict(current: impl Into<String>, expected: impl Into<String>) -> Self {
        CoreError::StateConflict {
            current: current.into(),
            expected: expected.into(),
        }
    }

    /// 创建无效配置错误
    pub fn invalid_config(field: &'static str, reason: &'static str) -> Self {
        CoreError::InvalidConfig { field, reason }
    }

    /// 创建内部错误
    pub fn internal(msg: impl Into<String>) -> Self {
        CoreError::Internal(msg.into())
    }

    /// 创建未知错误
    pub fn unknown(msg: impl Into<String>) -> Self {
        CoreError::Unknown(msg.into())
    }
}

/// 可记录的错误特征
pub trait LoggableError: fmt::Display {
    /// 是否为可恢复错误
    fn is_recoverable(&self) -> bool;

    /// 是否为安全相关错误
    fn is_security_related(&self) -> bool;

    /// 获取错误严重级别
    fn severity(&self) -> ErrorSeverity;
}

/// 错误严重级别(全 workspace 唯一定义)
///
/// 四级语义与其他平台错误体系的映射:
/// `Info`/`Warning`/`Error` 同名对应;`Critical` 即致命级
/// (等同部分平台错误体系中的 `Fatal`:系统不可用、不可恢复)。
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorSeverity {
    /// 信息级别(可恢复)
    Info,
    /// 警告级别(需要关注)
    Warning,
    /// 错误级别(操作失败)
    Error,
    /// 严重错误(致命级,等同 `Fatal`:系统不可用)
    Critical,
}

impl LoggableError for CoreError {
    fn is_recoverable(&self) -> bool {
        matches!(
            self,
            CoreError::QuotaExceeded { .. }
                | CoreError::ResourceNotFound { .. }
                | CoreError::ResourceAlreadyExists { .. }
        )
    }

    fn is_security_related(&self) -> bool {
        matches!(
            self,
            CoreError::OwnershipViolation { .. } | CoreError::InvalidAddressRange { .. }
        )
    }

    fn severity(&self) -> ErrorSeverity {
        match self {
            CoreError::OwnershipViolation { .. } => ErrorSeverity::Critical,
            CoreError::ResourcePoisoned { .. } => ErrorSeverity::Critical,
            CoreError::InvalidAddressRange { .. } => ErrorSeverity::Error,
            CoreError::ArithmeticOverflow { .. } => ErrorSeverity::Error,
            CoreError::StateConflict { .. } => ErrorSeverity::Warning,
            CoreError::InvalidConfig { .. } => ErrorSeverity::Warning,
            CoreError::QuotaExceeded { .. } => ErrorSeverity::Warning,
            CoreError::ResourceAlreadyExists { .. } => ErrorSeverity::Warning,
            CoreError::ResourceNotFound { .. } => ErrorSeverity::Info,
            CoreError::Internal(_) => ErrorSeverity::Error,
            CoreError::Unknown(_) => ErrorSeverity::Error,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_quota_exceeded_error() {
        let err = CoreError::quota_exceeded("frame", 1024, 2048);
        assert!(err.is_recoverable());
        assert!(!err.is_security_related());
        assert_eq!(err.severity(), ErrorSeverity::Warning);
        assert!(err.to_string().contains("frame"));
    }

    #[test]
    fn test_ownership_violation_error() {
        let err = CoreError::ownership_violation("pool", "other");
        assert!(!err.is_recoverable());
        assert!(err.is_security_related());
        assert_eq!(err.severity(), ErrorSeverity::Critical);
    }

    #[test]
    fn test_invalid_address_range_error() {
        let err = CoreError::invalid_address_range(0x1000, 256, 0x2000);
        assert!(!err.is_recoverable());
        assert!(err.is_security_related());
        assert_eq!(err.severity(), ErrorSeverity::Error);
    }

    #[test]
    fn test_arithmetic_overflow_error() {
        let err = CoreError::arithmetic_overflow("add", u64::MAX, 1);
        assert_eq!(err.severity(), ErrorSeverity::Error);
    }

    #[test]
    fn test_state_conflict_error() {
        let err = CoreError::state_conflict("active", "idle");
        assert_eq!(err.severity(), ErrorSeverity::Warning);
    }

    #[test]
    fn test_internal_error() {
        let err = CoreError::internal("something went wrong");
        assert_eq!(err.severity(), ErrorSeverity::Error);
    }

    // ===== CoreError 所有变体构造函数和 Display 输出 =====

    #[test]
    fn test_quota_exceeded_display() {
        let err = CoreError::quota_exceeded("memory", 1024, 2048);
        let msg = err.to_string();
        assert!(msg.contains("quota exceeded"));
        assert!(msg.contains("memory"));
        assert!(msg.contains("1024"));
        assert!(msg.contains("2048"));
    }

    #[test]
    fn test_resource_not_found_constructor_and_display() {
        let err = CoreError::resource_not_found(42, "frame");
        assert!(err.is_recoverable());
        assert!(!err.is_security_related());
        assert_eq!(err.severity(), ErrorSeverity::Info);

        let msg = err.to_string();
        assert!(msg.contains("resource not found"));
        assert!(msg.contains("42"));
        assert!(msg.contains("frame"));
    }

    #[test]
    fn test_resource_already_exists_constructor_and_display() {
        let err = CoreError::resource_already_exists(7, "connection");
        assert!(err.is_recoverable());
        assert!(!err.is_security_related());
        assert_eq!(err.severity(), ErrorSeverity::Warning);

        let msg = err.to_string();
        assert!(msg.contains("resource already exists"));
        assert!(msg.contains("7"));
        assert!(msg.contains("connection"));
    }

    #[test]
    fn test_resource_poisoned_constructor_and_display() {
        let err = CoreError::resource_poisoned(100, "corrupted data");
        assert!(!err.is_recoverable());
        assert!(!err.is_security_related());
        assert_eq!(err.severity(), ErrorSeverity::Critical);

        let msg = err.to_string();
        assert!(msg.contains("resource poisoned"));
        assert!(msg.contains("100"));
        assert!(msg.contains("corrupted data"));
    }

    #[test]
    fn test_ownership_violation_display() {
        let err = CoreError::ownership_violation("pool_a", "pool_b");
        let msg = err.to_string();
        assert!(msg.contains("ownership violation"));
        assert!(msg.contains("pool_a"));
        assert!(msg.contains("pool_b"));
    }

    #[test]
    fn test_invalid_address_range_display() {
        let err = CoreError::invalid_address_range(0x1000, 256, 0x2000);
        let msg = err.to_string();
        assert!(msg.contains("invalid address range"));
        assert!(msg.contains(&format!("{:x}", 0x1000)));
        assert!(msg.contains("256"));
    }

    #[test]
    fn test_arithmetic_overflow_display() {
        let err = CoreError::arithmetic_overflow("mul", 100, 200);
        let msg = err.to_string();
        assert!(msg.contains("arithmetic overflow"));
        assert!(msg.contains("mul"));
        assert!(msg.contains("100"));
        assert!(msg.contains("200"));
    }

    #[test]
    fn test_state_conflict_constructor_and_display() {
        let err = CoreError::state_conflict("running", "stopped");
        assert!(!err.is_recoverable());
        assert!(!err.is_security_related());
        assert_eq!(err.severity(), ErrorSeverity::Warning);

        let msg = err.to_string();
        assert!(msg.contains("state conflict"));
        assert!(msg.contains("running"));
        assert!(msg.contains("stopped"));
    }

    #[test]
    fn test_internal_error_constructor_and_display() {
        let err = CoreError::internal("fatal crash");
        assert!(!err.is_recoverable());
        assert!(!err.is_security_related());
        assert_eq!(err.severity(), ErrorSeverity::Error);

        let msg = err.to_string();
        assert!(msg.contains("internal error"));
        assert!(msg.contains("fatal crash"));
    }

    #[test]
    fn test_unknown_error_constructor_and_display() {
        let err = CoreError::unknown("mystery error");
        assert!(!err.is_recoverable());
        assert!(!err.is_security_related());
        assert_eq!(err.severity(), ErrorSeverity::Error);

        let msg = err.to_string();
        assert!(msg.contains("unknown error"));
        assert!(msg.contains("mystery error"));
    }

    // ===== ErrorSeverity 排序和比较 =====

    #[test]
    fn test_error_severity_equality() {
        assert_eq!(ErrorSeverity::Info, ErrorSeverity::Info);
        assert_eq!(ErrorSeverity::Warning, ErrorSeverity::Warning);
        assert_eq!(ErrorSeverity::Error, ErrorSeverity::Error);
        assert_eq!(ErrorSeverity::Critical, ErrorSeverity::Critical);
    }

    #[test]
    fn test_error_severity_clone_copy() {
        let s = ErrorSeverity::Warning;
        let s2 = s;
        assert_eq!(s, s2);
        let s3 = s;
        assert_eq!(s, s3);
    }

    #[test]
    fn test_error_severity_debug() {
        let s = format!("{:?}", ErrorSeverity::Critical);
        assert_eq!(s, "Critical");
    }

    // ===== is_recoverable / is_security_related 完整覆盖 =====

    #[test]
    fn test_all_recoverable_errors() {
        assert!(CoreError::quota_exceeded("mem", 0, 0).is_recoverable());
        assert!(CoreError::resource_not_found(0, "x").is_recoverable());
        assert!(CoreError::resource_already_exists(0, "x").is_recoverable());

        assert!(!CoreError::resource_poisoned(0, "x").is_recoverable());
        assert!(!CoreError::ownership_violation("a", "b").is_recoverable());
        assert!(!CoreError::invalid_address_range(0, 0, 0).is_recoverable());
        assert!(!CoreError::arithmetic_overflow("add", 0, 0).is_recoverable());
        assert!(!CoreError::state_conflict("a", "b").is_recoverable());
        assert!(!CoreError::internal("x").is_recoverable());
        assert!(!CoreError::unknown("x").is_recoverable());
    }

    #[test]
    fn test_all_security_related_errors() {
        assert!(CoreError::ownership_violation("a", "b").is_security_related());
        assert!(CoreError::invalid_address_range(0, 0, 0).is_security_related());

        assert!(!CoreError::quota_exceeded("mem", 0, 0).is_security_related());
        assert!(!CoreError::resource_not_found(0, "x").is_security_related());
        assert!(!CoreError::resource_already_exists(0, "x").is_security_related());
        assert!(!CoreError::resource_poisoned(0, "x").is_security_related());
        assert!(!CoreError::arithmetic_overflow("add", 0, 0).is_security_related());
        assert!(!CoreError::state_conflict("a", "b").is_security_related());
        assert!(!CoreError::internal("x").is_security_related());
        assert!(!CoreError::unknown("x").is_security_related());
    }

    // ===== LoggableError trait 对象安全测试 =====

    #[test]
    fn test_loggable_error_trait_object() {
        let err: Box<dyn LoggableError> = Box::new(CoreError::internal("test"));
        assert!(!err.is_recoverable());
        assert!(!err.is_security_related());
        assert_eq!(err.severity(), ErrorSeverity::Error);
        assert!(err.to_string().contains("internal error"));
    }
}