#![no_std]
#![feature(step_trait, const_trait_impl, never_type, decl_macro)]
#![allow(clippy::new_without_default)]

use core::ops::Range;

use alloc::vec::Vec;
use cpu::{CpuData, CpuFeatureSet, CpuImpl, IpiQueue};
use device_api::interrupt::LocalInterruptController;
use task::Scheduler;

extern crate alloc;

#[macro_use]
pub mod macros;

pub mod cpu;
pub mod guard;
pub mod mem;
pub mod sync;
pub mod task;
pub mod util;

#[cfg(any(target_arch = "aarch64", target_arch = "x86_64", rust_analyzer))]
pub const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000;
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
pub const KERNEL_VIRT_OFFSET: usize = 0xFFFFFFF000000000;

pub trait Architecture: Sized + 'static {
    type PerCpuData: CpuData;
    type CpuFeatures: CpuFeatureSet;

    type BreakpointType;
    const BREAKPOINT_VALUE: Self::BreakpointType;

    // Cpu management

    /// # Safety
    ///
    /// Precondition: this function has not yet been called on the local CPU.
    unsafe fn set_local_cpu(cpu: *mut ());
    fn local_cpu() -> *mut ();
    /// # Safety
    ///
    /// Precondition: this function has not yet been called on the local CPU.
    unsafe fn init_ipi_queues(queues: Vec<IpiQueue<Self>>);

    fn ipi_queue(cpu_id: u32) -> Option<&'static IpiQueue<Self>>;

    /// # Safety
    ///
    /// Precondition: this function has not yet been called on the local CPU.
    unsafe fn init_local_cpu<S: Scheduler + 'static>(id: Option<u32>, data: Self::PerCpuData);

    fn idle_task() -> extern "C" fn(usize) -> !;

    fn cpu_count() -> usize;
    fn cpu_index<S: Scheduler + 'static>() -> u32;

    // Interrupt management
    fn interrupt_mask() -> bool;
    /// # Safety
    ///
    /// The caller must ensure it is actually safe to enable interrupts in the current context.
    unsafe fn set_interrupt_mask(mask: bool) -> bool;
    fn wait_for_interrupt();

    fn halt() -> !;

    // Architectural devices
    fn local_interrupt_controller() -> Option<&'static dyn LocalInterruptController> {
        None
    }

    #[allow(unused)]
    fn cpu_available_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
        None
    }
    #[allow(unused)]
    fn cpu_enabled_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
        None
    }

    // Cache/barrier operation

    fn load_barrier();
    fn store_barrier();
    fn memory_barrier() {
        Self::store_barrier();
        Self::load_barrier();
    }

    /// Flushes/invalidates a range of virtual memory from the CPU's data cache.
    fn flush_virtual_range(range: Range<usize>);
}
