mod switch;
mod deprecated;

use core::arch::asm;

#[repr(C)]
pub struct Thread {
    id: usize,
    /// This shall be default before the program is interrupted, otherwise it will store
    /// CPU registers etc to be restored on context switch.
    ctx: ThreadContext,
}

/// CPU state to be saved on context switches.
#[repr(C)]
#[derive(Default)]
pub struct ThreadContext {
    /// Accumulator register.
    rax: u64,
    /// Base register.
    rbx: u64,
    /// Counter register.
    rcx: u64,
    /// Data register.
    rdx: u64,
    /// Source index register.
    rsi: u64,
    /// Destination index register.
    rdi: u64,
    /// Base pointer register.
    rbp: u64,
    /// Stack pointer register.
    rsp: u64,
    /// An extended register.
    r8: u64,
    /// An extended register.
    r9: u64,
    /// An extended register.
    r10: u64,
    /// An extended register.
    r11: u64,
    /// An extended register.
    r12: u64,
    /// An extended register.
    r13: u64,
    /// An extended register.
    r14: u64,
    /// An extended register.
    r15: u64,
    /// The instruction pointer.
    rip: u64,
    /// RFLAGS register.
    rflags: u64,
}

impl ThreadContext {
    /// Saves the current registers of the CPU before a context switch
    /// to be restored later.
    ///
    /// # Notes
    ///
    /// This function should ONLY be called in interrupt handlers such
    /// as that of the timer. This will then save registers as required
    ///
    ///
    /// # Safety
    ///
    /// This function is unsafe because of the usage of inline ASM.
    #[inline(always)]
    pub unsafe fn save_registers() -> Self {
        let mut context = Self::default();
        unsafe {
            asm!(
                "mov {0}, rax",
                "mov {1}, rbx",
                "mov {2}, rcx",
                "mov {3}, rdx",
                "mov {4}, rsi",
                "mov {5}, rdi",
                "mov {6}, rbp",
                "mov {7}, rsp",
                "mov {8}, r8",
                "mov {9}, r9",
                "mov {10}, r10",
                "mov {11}, r11",
                "mov {12}, r12",
                "mov {13}, r13",
                "mov {14}, r14",
                "mov {15}, r15",
                "lea {16}, [rip]",
                "pushf",
                "pop {17}",
                out(reg) context.rax,
                out(reg) context.rbx,
                out(reg) context.rcx,
                out(reg) context.rdx,
                out(reg) context.rsi,
                out(reg) context.rdi,
                out(reg) context.rbp,
                out(reg) context.rsp,
                out(reg) context.r8,
                out(reg) context.r9,
                out(reg) context.r10,
                out(reg) context.r11,
                out(reg) context.r12,
                out(reg) context.r13,
                out(reg) context.r14,
                out(reg) context.r15,
                out(reg) context.rip,
                out(reg) context.rflags,
            );
        }

        context
    }
}
