//! task 任务定义
#![no_std]

use core::{
    mem::offset_of,
    sync::atomic::{AtomicU32, AtomicUsize, Ordering},
};

/// task base 定义
///
/// 汇编必须有一些需要访问的变量，因此该结构用于导出必要的变
#[derive(Default)]
#[repr(C)]
pub struct TaskBase {
    // 任务内核栈起始地址
    stack: AtomicUsize,
    // 任务线程地址上限限制
    thread_addr_limit: AtomicUsize,
    // 线程 flags
    thread_flags: AtomicU32,
    // 线程抢占计数
    thread_preempt: AtomicU32,
}

impl TaskBase {
    /// 构造 task base
    pub const fn new() -> Self {
        Self {
            stack: AtomicUsize::new(0),
            thread_addr_limit: AtomicUsize::new(0),
            thread_flags: AtomicU32::new(0),
            thread_preempt: AtomicU32::new(0),
        }
    }

    /// 设置任务栈基址
    pub fn set_stack(&self, stack_base: usize) {
        self.stack.store(stack_base, Ordering::Relaxed);
    }

    /// 任务栈基地址
    #[inline(always)]
    pub fn stack(&self) -> usize {
        self.stack.load(Ordering::Relaxed)
    }

    /// 设置任务抢占计数
    #[inline(always)]
    pub fn set_preempt(&self, val: u32) {
        self.thread_preempt.store(val, Ordering::Relaxed);
    }

    /// 获取任务抢占计数
    #[inline(always)]
    pub fn preempt(&self) -> u32 {
        self.thread_preempt.load(Ordering::Relaxed)
    }

    /// 增加任务抢占计数
    #[inline(always)]
    pub fn preempt_add(&self, val: u32) {
        self.thread_preempt.fetch_add(val, Ordering::Relaxed);
    }

    /// 减少任务抢占计数
    #[inline(always)]
    pub fn preempt_sub(&self, val: u32) {
        self.thread_preempt.fetch_sub(val, Ordering::Relaxed);
    }

    /// 设置任务flags
    #[inline(always)]
    pub fn set_flags(&self, flags: u32) {
        self.thread_flags.store(flags, Ordering::Relaxed);
    }

    /// 设置任务falgs bit
    #[inline(always)]
    pub fn set_flags_bit(&self, bit: u32) {
        self.thread_flags.fetch_or(1 << bit, Ordering::Relaxed);
    }

    /// 获取任务flags
    #[inline(always)]
    pub fn flags(&self) -> u32 {
        self.thread_flags.load(Ordering::Relaxed)
    }

    /// 测试任务flags bit是否设置
    #[inline(always)]
    pub fn test_flags_bit(&self, bit: u32) -> bool {
        self.thread_flags.load(Ordering::Relaxed) & (1 << bit) != 0
    }
}

/// `TSK_STACK`
pub const TSK_STACK: usize = offset_of!(TaskBase, stack);
/// `TSK_TI_ADDR_LIMIT`
pub const TSK_TI_ADDR_LIMIT: usize = offset_of!(TaskBase, thread_addr_limit);
/// `TSK_TI_FLAGS`
pub const TSK_TI_FLAGS: usize = offset_of!(TaskBase, thread_flags);
/// `TSK_TI_PREEMPT`
pub const TSK_TI_PREEMPT: usize = offset_of!(TaskBase, thread_preempt);

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

    #[test]
    fn test() {
        assert_eq!(TSK_STACK, 0);
        assert_eq!(TSK_TI_ADDR_LIMIT, 8);
        assert_eq!(TSK_TI_FLAGS, 16);
        assert_eq!(TSK_TI_PREEMPT, 20);
    }
}
