#![doc(html_no_source)]
//! This crate contains safe zero-cost abstractions over the raw C types in [gc_abi_sys].
//! Every interaction with the core gateway should be done through these abstractions.
//!
//! # Accessing the raw C types
//! Every abstraction implements the [GCAbiConversion] trait, which allows for easy conversion between the Rust and C types.
//! Some raw C types can also be accessed through the [raw] module.
mod datapoint;
mod datapoint_value;
mod datapoint_value_quality;
mod log;
mod plugin_config;
mod plugin_info;
mod plugin_interface;
pub mod error;
pub mod raw;

pub use log::GCLogLevel;
pub type GCDatapointID = gc_abi_sys::GCDatapointIdentifier;
pub use datapoint::GCDatapoint;
pub use datapoint_value::{GCDatapointValue, GCDatapointValueType};
pub use datapoint_value_quality::GCDatapointValueQuality;
pub use plugin_config::GCPluginConfig;
pub use plugin_info::GCPluginInfo;
pub use plugin_interface::GCCoreExportedFunctions;
pub use plugin_interface::GCPluginInterface;

/// Trait for converting between Rust and C types
/// Provides methods for converting between raw and abstraction types.
///
/// # Safety
/// Implementors must ensure that [GCAbiConversion::CType] has the same memory layout as whatever implements [GCAbiConversion]
pub unsafe trait GCAbiConversion: Sized {
    type CType: Sized;

    /// Convert from the C type to the Rust type
    fn from_c(c_type: Self::CType) -> Self;

    /// Convert from the Rust type to the C type
    fn into_c(self) -> Self::CType;

    /// Get a reference to the C type
    fn ref_c(&self) -> &Self::CType {
        // Safety:
        // As long as the layout of the two types is the same, this is safe
        unsafe { &*(self as *const Self as *const Self::CType) }
    }

    /// Get a reference to the converted type
    fn from_c_ref(c_type: &Self::CType) -> &Self {
        // Safety:
        // As long as the layout of the two types is the same, this is safe
        unsafe { &*(c_type as *const Self::CType as *const Self) }
    }

    /// Get a mutable reference to the C type
    ///
    /// # Safety
    /// Assumes the pointer is valid and not null
    /// The caller is responsible for dealing with the lifetime of the pointer
    unsafe fn from_c_ptr(ptr: *const Self::CType) -> &'static Self {
        unsafe {
            let result = ptr as *const Self;
            &*result
        }
    }

    /// Get a immutable reference to the C type
    ///
    /// # Safety
    /// The caller is responsible for manually handle the lifetime of the pointer
    unsafe fn as_ptr(&self) -> *const Self::CType {
        self as *const Self as *mut Self::CType
    }

    /// Get a mutable reference to the C type
    ///
    /// # Safety
    /// The caller is responsible for dealing with the lifetime of the pointer
    /// Also, the caller must not mutate both the reference at pointer at the same time
    /// as this goes against the borrowing rules
    unsafe fn as_mut_ptr(&mut self) -> *mut Self::CType {
        self as *mut Self as *mut Self::CType
    }
}
