wdext 0.1.0

A DbgEng wrapper framework
// SPDX-FileCopyrightText: 2026 takubokudori
// SPDX-License-Identifier: MIT OR Apache-2.0
use crate::{
    data::VarType,
    dbgeng::WinResult,
    dbgmodel::{
        DebugHostContext, DebugHostModule, DebugHostSymbol,
        DebugHostSymbolEnumerator,
    },
    impl_debug_interface, pcw,
};
use windows::Win32::System::Diagnostics::Debug::Extensions::{
    ArrayDimension, CallingConventionKind, IDebugHostType, IDebugHostType2,
    IntrinsicKind, PointerKind, SymbolKind, TypeKind, VarArgsKind,
};
use windy::WStr;

impl_debug_interface!(
    DebugHostType,
    DebugHostTypeRef,
    IDebugHostType2,
    IDebugHostType
);

impl DebugHostType {
    pub fn get_context(&self) -> WinResult<DebugHostContext> {
        unsafe { Ok(self.0.GetContext()?.into()) }
    }

    pub fn enumerate_children(
        &self,
        kind: SymbolKind,
        name: impl AsRef<WStr>,
    ) -> WinResult<DebugHostSymbolEnumerator> {
        unsafe { Ok(self.0.EnumerateChildren(kind, pcw!(name))?.into()) }
    }

    pub fn get_symbol_kind(&self) -> WinResult<SymbolKind> {
        unsafe { self.0.GetSymbolKind() }
    }

    pub fn get_name(&self) -> WinResult<String> {
        unsafe { Ok(self.0.GetName()?.to_string()) }
    }

    pub fn get_type(&self) -> WinResult<Self> {
        unsafe { Ok(self.0.GetType()?.into()) }
    }

    pub fn get_containing_module(&self) -> WinResult<DebugHostModule> {
        unsafe { Ok(self.0.GetContainingModule()?.into()) }
    }

    pub fn get_type_kind(&self) -> WinResult<TypeKind> {
        unsafe { self.0.GetTypeKind() }
    }

    pub fn get_size(&self) -> WinResult<u64> { unsafe { self.0.GetSize() } }

    pub fn get_base_type(&self) -> WinResult<Self> {
        unsafe { Ok(self.0.GetBaseType()?.into()) }
    }

    pub fn get_hash_code(&self) -> WinResult<u32> {
        unsafe { self.0.GetHashCode() }
    }

    pub fn get_intrinsic_type(&self) -> WinResult<(IntrinsicKind, VarType)> {
        unsafe {
            let mut intrinsic_kind = Default::default();
            let mut carrier_type = Default::default();
            self.0.GetIntrinsicType(
                Some(&mut intrinsic_kind),
                Some(&mut carrier_type),
            )?;

            Ok((intrinsic_kind, VarType::from_bits_truncate(carrier_type)))
        }
    }

    /// Returns `(lsbOfField, lengthOfField)`.
    pub fn get_bit_field(&self) -> WinResult<(u32, u32)> {
        unsafe {
            let mut lsb_of_field = 0;
            let mut length_of_field = 0;
            self.0
                .GetBitField(&mut lsb_of_field, &mut length_of_field)?;
            Ok((lsb_of_field, length_of_field))
        }
    }

    pub fn get_pointer_kind(&self) -> WinResult<PointerKind> {
        unsafe { self.0.GetPointerKind() }
    }

    pub fn get_member_type(&self) -> WinResult<Self> {
        unsafe { Ok(self.0.GetMemberType()?.into()) }
    }

    pub fn create_pointer_to(&self, kind: PointerKind) -> WinResult<Self> {
        unsafe { Ok(self.0.CreatePointerTo(kind)?.into()) }
    }

    pub fn get_array_dimensionality(&self) -> WinResult<u64> {
        unsafe { self.0.GetArrayDimensionality() }
    }

    /*
    pub fn get_array_dimensions(
        &self,
        dimensions: &mut [ArrayDimension],
    ) -> WinResult<()> {
        // TODO: Is this an `S_FALSE`-style result?
        unsafe { self.0.GetArrayDimensions(dimensions) }
    }
    */

    pub fn create_array_of(
        &self,
        dimensions: &[ArrayDimension],
    ) -> WinResult<Self> {
        unsafe { Ok(self.0.CreateArrayOf(dimensions)?.into()) }
    }

    pub fn get_function_calling_convention(
        &self,
    ) -> WinResult<CallingConventionKind> {
        unsafe { self.0.GetFunctionCallingConvention() }
    }

    pub fn get_function_return_type(&self) -> WinResult<Self> {
        unsafe { Ok(self.0.GetFunctionReturnType()?.into()) }
    }

    pub fn get_function_parameter_type_count(&self) -> WinResult<u64> {
        unsafe { self.0.GetFunctionParameterTypeCount() }
    }

    pub fn get_function_parameter_type_at(&self, i: u64) -> WinResult<Self> {
        unsafe { Ok(self.0.GetFunctionParameterTypeAt(i)?.into()) }
    }

    pub fn is_generic(&self) -> WinResult<bool> {
        unsafe { self.0.IsGeneric() }
    }

    pub fn get_generic_argument_count(&self) -> WinResult<u64> {
        unsafe { self.0.GetGenericArgumentCount() }
    }

    pub fn get_generic_argument_at(
        &self,
        i: u64,
    ) -> WinResult<DebugHostSymbol> {
        unsafe { Ok(self.0.GetGenericArgumentAt(i)?.into()) }
    }
}

// IDebugHostType2
impl DebugHostType {
    pub fn is_typedef(&self) -> WinResult<bool> {
        unsafe { self.0.IsTypedef() }
    }

    pub fn get_typedef_base_type(&self) -> WinResult<Self> {
        unsafe { Ok(self.0.GetTypedefBaseType()?.into()) }
    }

    pub fn get_typedef_final_base_type(&self) -> WinResult<Self> {
        unsafe { Ok(self.0.GetTypedefFinalBaseType()?.into()) }
    }

    pub fn get_function_var_args_kind(&self) -> WinResult<VarArgsKind> {
        unsafe { self.0.GetFunctionVarArgsKind() }
    }

    pub fn get_function_instance_pointer_type(&self) -> WinResult<Self> {
        unsafe { Ok(self.0.GetFunctionInstancePointerType()?.into()) }
    }
}

// IDebugHostType3
impl DebugHostType {
    // GetContainingType
}

// IDebugHostType4
impl DebugHostType {
    // GetExtendedArrayHeaderSize

    // GetExtendedArrayDimensions

    // GetUDTKind
}

// IDebugHostType5
impl DebugHostType {
    // IsBaseTypeOf
}

// IDebugHostType6
impl DebugHostType {
    // GetTaggedUnionTag

    // GetTaggedUnionTagRanges

    // UpcastToTaggedUnionType
}