zenith-foundation 0.1.0

Zenith 核心基础设施:统一错误类型、FrameToken 所有权令牌、FramePool、分层资源账本、恒定时间比较
Documentation
//! 所有权令牌模块
//!
//! 实现 FrameToken 所有权令牌,通过 `PhantomData<*const ()>` 在编译期保证
//! 所有权唯一,防止资源被复制或伪造(!Copy + !Clone)。

use std::fmt;
use std::marker::PhantomData;

use crate::error::{CoreError, CoreResult};
use crate::frame::FrameId;

/// 所有权令牌
///
/// 每个令牌唯一对应一个 Frame,通过类型系统在编译期保证:
/// - 不可跨线程(!Send + !Sync,通过 `PhantomData<*const ()>` 实现:
///   原始指针自动不实现 Send/Sync,令牌无法传递或共享到其他线程)
/// - 不可复制/克隆(!Copy + !Clone,通过不 derive 相应 trait 实现)
/// - 不可在外部构造(`pub(crate)` 构造函数)
///
/// # 所有权守恒
///
/// 令牌的生命周期必须严格遵循以下规则:
/// 1. 令牌创建后只能有一个所有者
/// 2. 所有权转移必须是原子操作
/// 3. 令牌销毁前必须归还到 FramePool
pub struct FrameToken {
    /// Frame ID
    frame_id: FrameId,
    /// 域ID
    domain_id: u32,
    /// 代际号
    generation: u64,
    /// Epoch编号
    epoch: u64,
    /// PhantomData 用于禁用 Send 和 Sync:
    /// 原始指针 *const () 自动不实现 Send/Sync,经 PhantomData 传递到整个结构体,
    /// 使令牌被类型系统钉死在创建它的 Worker 线程上
    _not_send_sync: PhantomData<*const ()>,
}

impl fmt::Debug for FrameToken {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FrameToken")
            .field("frame_id", &self.frame_id)
            .field("domain_id", &self.domain_id)
            .field("generation", &self.generation)
            .field("epoch", &self.epoch)
            .finish()
    }
}

impl FrameToken {
    /// 创建新的所有权令牌
    ///
    /// # Arguments
    /// * `frame_id` - Frame ID
    /// * `domain_id` - 域ID
    /// * `generation` - 代际号
    /// * `epoch` - Epoch编号
    ///
    /// # Returns
    /// 新的 FrameToken 实例
    ///
    /// # Safety
    /// 此方法仅限 crate 内部使用,外部禁止构造令牌
    pub(crate) fn new(
        frame_id: FrameId,
        domain_id: u32,
        generation: u64,
        epoch: u64,
    ) -> Self {
        Self {
            frame_id,
            domain_id,
            generation,
            epoch,
            _not_send_sync: PhantomData,
        }
    }

    /// 获取 Frame ID
    pub fn frame_id(&self) -> FrameId {
        self.frame_id
    }

    /// 获取域ID
    pub fn domain_id(&self) -> u32 {
        self.domain_id
    }

    /// 获取代际号
    pub fn generation(&self) -> u64 {
        self.generation
    }

    /// 获取Epoch编号
    pub fn epoch(&self) -> u64 {
        self.epoch
    }

    /// 验证令牌是否属于指定域和代际
    ///
    /// 使用恒定时间比较防止时序侧信道攻击。
    ///
    /// # Arguments
    /// * `expected_domain` - 期望的域ID
    /// * `expected_generation` - 期望的代际号
    ///
    /// # Returns
    /// * `Ok(())` - 验证通过
    /// * `Err(CoreError::OwnershipViolation)` - 验证失败
    pub fn verify_ownership(
        &self,
        expected_domain: u32,
        expected_generation: u64,
    ) -> CoreResult<()> {
        let domain_ok = crate::constant_time_eq_u32(self.domain_id, expected_domain);
        let gen_ok = crate::constant_time_eq_u64(self.generation, expected_generation);

        if domain_ok && gen_ok {
            Ok(())
        } else {
            Err(CoreError::ownership_violation(
                if domain_ok { "valid domain" } else { "invalid domain" },
                if gen_ok { "valid generation" } else { "invalid generation" },
            ))
        }
    }

    /// 验证令牌是否属于指定Epoch
    ///
    /// 使用恒定时间比较防止时序侧信道攻击。
    ///
    /// # Arguments
    /// * `expected_epoch` - 期望的Epoch编号
    ///
    /// # Returns
    /// * `Ok(())` - 验证通过
    /// * `Err(CoreError::StateConflict)` - 验证失败
    pub fn verify_epoch(&self, expected_epoch: u64) -> CoreResult<()> {
        if crate::constant_time_eq_u64(self.epoch, expected_epoch) {
            Ok(())
        } else {
            Err(CoreError::state_conflict(
                format!("epoch={}", self.epoch),
                format!("epoch={}", expected_epoch),
            ))
        }
    }

    /// 消费令牌并获取 Frame ID
    ///
    /// 此方法消费令牌,返回 Frame ID。
    /// 令牌被消费后不可再使用(self 在函数结束时自动释放所有权)。
    ///
    /// # Returns
    /// Frame ID
    pub fn into_frame_id(self) -> FrameId {
        self.frame_id
    }
}

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

    #[test]
    fn test_token_creation() {
        let token = FrameToken::new(FrameId::new(1), 0, 1, 0);
        assert_eq!(token.frame_id(), FrameId::new(1));
        assert_eq!(token.domain_id(), 0);
        assert_eq!(token.generation(), 1);
        assert_eq!(token.epoch(), 0);
    }

    #[test]
    fn test_verify_ownership_success() {
        let token = FrameToken::new(FrameId::new(1), 0, 1, 0);
        assert!(token.verify_ownership(0, 1).is_ok());
    }

    #[test]
    fn test_verify_ownership_failure_domain() {
        let token = FrameToken::new(FrameId::new(1), 0, 1, 0);
        let result = token.verify_ownership(1, 1);
        assert!(result.is_err());
    }

    #[test]
    fn test_verify_ownership_failure_generation() {
        let token = FrameToken::new(FrameId::new(1), 0, 1, 0);
        let result = token.verify_ownership(0, 2);
        assert!(result.is_err());
    }

    #[test]
    fn test_verify_epoch_success() {
        let token = FrameToken::new(FrameId::new(1), 0, 1, 42);
        assert!(token.verify_epoch(42).is_ok());
    }

    #[test]
    fn test_verify_epoch_failure() {
        let token = FrameToken::new(FrameId::new(1), 0, 1, 42);
        let result = token.verify_epoch(43);
        assert!(result.is_err());
    }

    #[test]
    fn test_into_frame_id() {
        let token = FrameToken::new(FrameId::new(100), 0, 1, 0);
        let id = token.into_frame_id();
        assert_eq!(id, FrameId::new(100));
    }

    #[test]
    fn test_token_is_not_copy() {
        // 编译期检查:FrameToken 不可复制
        let token = FrameToken::new(FrameId::new(1), 0, 1, 0);
        let _token2 = token; // 所有权转移
        // let _token3 = token; // 编译错误:value borrowed after move
    }

    // ===== verify_ownership 双条件同时失败 =====

    #[test]
    fn test_verify_ownership_both_fail() {
        let token = FrameToken::new(FrameId::new(1), 0, 1, 0);
        let result = token.verify_ownership(99, 99);
        assert!(result.is_err());
    }

    // ===== verify_epoch 测试(gen=0 边界情况) =====

    #[test]
    fn test_verify_epoch_success_gen0() {
        let token = FrameToken::new(FrameId::new(1), 0, 0, 42);
        assert!(token.verify_epoch(42).is_ok());
    }

    #[test]
    fn test_verify_epoch_failure_gen0() {
        let token = FrameToken::new(FrameId::new(1), 0, 0, 42);
        let result = token.verify_epoch(100);
        assert!(result.is_err());
    }

    #[test]
    fn test_verify_epoch_zero() {
        let token = FrameToken::new(FrameId::new(1), 0, 0, 0);
        assert!(token.verify_epoch(0).is_ok());
        assert!(token.verify_epoch(1).is_err());
    }

    #[test]
    fn test_verify_epoch_max() {
        let token = FrameToken::new(FrameId::new(1), 0, 0, u64::MAX);
        assert!(token.verify_epoch(u64::MAX).is_ok());
        assert!(token.verify_epoch(u64::MAX - 1).is_err());
    }

    // ===== Debug 输出格式测试 =====

    #[test]
    fn test_token_debug_format() {
        let token = FrameToken::new(FrameId::new(42), 7, 3, 5);
        let debug_str = format!("{:?}", token);
        assert!(debug_str.contains("FrameToken"));
        assert!(debug_str.contains("frame_id"));
        assert!(debug_str.contains("domain_id"));
        assert!(debug_str.contains("generation"));
        assert!(debug_str.contains("epoch"));
    }

    // ===== FrameId From<u32> trait 测试 =====

    #[test]
    fn test_frame_id_from_u32_trait() {
        let id: FrameId = 123u32.into();
        assert_eq!(id.value(), 123);
        assert_eq!(id, FrameId::new(123));
    }

    #[test]
    fn test_frame_id_from_u32_zero() {
        let id: FrameId = 0u32.into();
        assert_eq!(id.value(), 0);
    }

    #[test]
    fn test_frame_id_from_u32_max() {
        let id: FrameId = u32::MAX.into();
        assert_eq!(id.value(), u32::MAX);
    }

    // ===== 边界值测试 =====

    #[test]
    fn test_token_boundary_values() {
        let token = FrameToken::new(
            FrameId::new(u32::MAX),
            u32::MAX,
            u64::MAX,
            u64::MAX,
        );
        assert_eq!(token.frame_id().value(), u32::MAX);
        assert_eq!(token.domain_id(), u32::MAX);
        assert_eq!(token.generation(), u64::MAX);
        assert_eq!(token.epoch(), u64::MAX);
    }

    // ===== into_frame_id 测试 =====

    #[test]
    fn test_into_frame_id_consumes_token() {
        let token = FrameToken::new(FrameId::new(99), 0, 0, 0);
        let id = token.into_frame_id();
        assert_eq!(id, FrameId::new(99));
    }
}