wdext 0.1.0

A DbgEng wrapper framework
// SPDX-FileCopyrightText: 2026 takubokudori
// SPDX-License-Identifier: MIT OR Apache-2.0
//! IDebugBreakpoint
use crate::dbgeng::{client::DebugClient, *};
use windows::core::GUID;
use windy::{ACPStr, ACPString, WStr, WString};

impl_debug_interface!(
    DebugBreakpoint,
    DebugBreakpointRef,
    IDebugBreakpoint3,
    IDebugBreakpoint
);

/// IDebugBreakpoint
impl DebugBreakpoint {
    pub fn get_id(&self) -> WinResult<BreakpointId> {
        unsafe { Ok(self.0.GetId()?.into()) }
    }

    pub fn get_type(&self) -> WinResult<(DebugBreakpointTypes, ProcessorType)> {
        let mut break_type = 0;
        let mut proc_type = 0;
        unsafe {
            self.0.GetType(&mut break_type, &mut proc_type)?;
            Ok((
                DebugBreakpointTypes::try_from(break_type)
                    .expect("Invalid break type"),
                ProcessorType::from(proc_type),
            ))
        }
    }

    pub fn get_adder(&self) -> WinResult<DebugClient> {
        unsafe { DebugClient::from_interface(&self.0.GetAdder()?) }
    }

    pub fn get_flags(&self) -> WinResult<DebugBreakpointFlags> {
        unsafe {
            Ok(DebugBreakpointFlags::from_bits_retain(self.0.GetFlags()?))
        }
    }

    pub fn add_flags(
        &self,
        breakpoint_flags: DebugBreakpointFlags,
    ) -> WinResult<()> {
        unsafe { self.0.AddFlags(breakpoint_flags.bits()) }
    }

    pub fn remove_flags(&self, flags: DebugBreakpointFlags) -> WinResult<()> {
        unsafe { self.0.RemoveFlags(flags.bits()) }
    }

    pub fn set_flags(&self, flags: DebugBreakpointFlags) -> WinResult<()> {
        unsafe { self.0.SetFlags(flags.bits()) }
    }

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

    pub fn set_offset(&self, offset: DebuggeeOffset) -> WinResult<()> {
        unsafe { self.0.SetOffset(offset) }
    }

    /// Returns `(Size, DebugBreakAccessTypes)`.
    pub fn get_data_parameters(
        &self,
    ) -> WinResult<(u32, DebugBreakAccessTypes)> {
        let mut size = 0;
        let mut access_type = 0;
        unsafe {
            self.0.GetDataParameters(&mut size, &mut access_type)?;
            Ok((size, DebugBreakAccessTypes::from_bits_retain(access_type)))
        }
    }

    pub fn set_data_parameters(
        &self,
        size: u32,
        access_type: DebugBreakAccessTypes,
    ) -> WinResult<()> {
        unsafe { self.0.SetDataParameters(size, access_type.bits()) }
    }

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

    pub fn set_pass_count(&self, count: u32) -> WinResult<()> {
        unsafe { self.0.SetPassCount(count) }
    }

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

    pub fn get_match_thread_id(&self) -> WinResult<EngineThreadId> {
        unsafe { Ok(self.0.GetMatchThreadId()?.into()) }
    }

    pub fn set_match_thread_id(&self, thread: EngineThreadId) -> WinResult<()> {
        unsafe { self.0.SetMatchThreadId(thread.into()) }
    }

    pub fn get_command(&self) -> WinResult<ACPString> {
        unsafe {
            astring_with_capacity(64, |v, s| {
                vcall!(self, GetCommand, pa!(v), v.len().try_into().unwrap(), s)
            })
        }
    }

    pub fn set_command(&self, command: impl AsRef<ACPStr>) -> WinResult<()> {
        unsafe { self.0.SetCommand(pca!(command)) }
    }

    pub fn get_offset_expression(&self) -> WinResult<ACPString> {
        unsafe {
            astring_with_capacity(64, |v, s| {
                vcall!(
                    self,
                    GetOffsetExpression,
                    pa!(v),
                    v.len().try_into().unwrap(),
                    s
                )
            })
        }
    }

    pub fn set_offset_expression(
        &self,
        expression: impl AsRef<ACPStr>,
    ) -> WinResult<()> {
        unsafe { self.0.SetOffsetExpression(pca!(expression)) }
    }

    pub fn get_parameters(&self) -> WinResult<DebugBreakpointParameters> {
        unsafe {
            let mut param: DEBUG_BREAKPOINT_PARAMETERS = core::mem::zeroed();
            self.0.GetParameters(&mut param)?;
            Ok(DebugBreakpointParameters(param))
        }
    }
}

// IDebugBreakpoint2
impl DebugBreakpoint {
    pub fn get_command_wide(&self) -> WinResult<WString> {
        unsafe {
            wstring_with_capacity(64, |v, s| {
                vcall!(
                    self,
                    GetCommandWide,
                    pw!(v),
                    v.len().try_into().unwrap(),
                    s
                )
            })
        }
    }

    pub fn set_command_wide(&self, command: impl AsRef<WStr>) -> WinResult<()> {
        unsafe { self.0.SetCommandWide(pcw!(command)) }
    }

    pub fn get_offset_expression_wide(&self) -> WinResult<WString> {
        unsafe {
            wstring_with_capacity(64, |v, s| {
                vcall!(
                    self,
                    GetOffsetExpressionWide,
                    pw!(v),
                    v.len().try_into().unwrap(),
                    s
                )
            })
        }
    }

    pub fn set_offset_expression_wide(
        &self,
        expression: impl AsRef<WStr>,
    ) -> WinResult<()> {
        unsafe { self.0.SetOffsetExpressionWide(pcw!(expression)) }
    }
}

// IDebugBreakpoint3
impl DebugBreakpoint {
    pub fn get_guid(&self) -> WinResult<GUID> { unsafe { self.0.GetGuid() } }
}