use std::{
collections::{HashMap, HashSet},
fmt::Debug,
hash::Hash,
};
use vmi_core::{AddressContext, View};
pub trait KeyType: Debug + Copy + Eq + Hash {}
impl<T> KeyType for T where T: Debug + Copy + Eq + Hash {}
pub trait TagType: Debug + Copy + Eq + Hash {}
impl<T> TagType for T where T: Debug + Copy + Eq + Hash {}
pub(super) type ActiveBreakpoints<Key, Tag> =
HashMap<(Key, AddressContext), HashSet<Breakpoint<Key, Tag>>>;
pub(super) type PendingBreakpoints<Key, Tag> = HashSet<Breakpoint<Key, Tag>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Breakpoint<Key, Tag>
where
Key: KeyType,
Tag: TagType,
{
pub(super) ctx: AddressContext,
pub(super) view: View,
pub(super) global: bool,
pub(super) key: Key,
pub(super) tag: Tag,
}
impl<Key, Tag> Breakpoint<Key, Tag>
where
Key: KeyType,
Tag: TagType,
{
pub fn ctx(&self) -> AddressContext {
self.ctx
}
pub fn view(&self) -> View {
self.view
}
pub fn global(&self) -> bool {
self.global
}
pub fn key(&self) -> Key {
self.key
}
pub fn tag(&self) -> Tag {
self.tag
}
}
#[derive(Debug)]
pub struct BreakpointBuilder {
ctx: AddressContext,
view: View,
global: bool,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct BreakpointBuilderWithKey<Key>
where
Key: KeyType,
{
ctx: AddressContext,
view: View,
global: bool,
key: Key,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct BreakpointBuilderWithTag<Tag>
where
Tag: TagType,
{
ctx: AddressContext,
view: View,
global: bool,
tag: Tag,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct BreakpointBuilderWithKeyTag<Key, Tag>
where
Key: KeyType,
Tag: TagType,
{
ctx: AddressContext,
view: View,
global: bool,
key: Key,
tag: Tag,
}
impl Breakpoint<(), ()> {
#[expect(clippy::new_ret_no_self)]
pub fn new(ctx: impl Into<AddressContext>, view: View) -> BreakpointBuilder {
BreakpointBuilder::new(ctx, view)
}
}
impl BreakpointBuilder {
pub fn new(ctx: impl Into<AddressContext>, view: View) -> Self {
Self {
ctx: ctx.into(),
view,
global: false,
}
}
pub fn global(self) -> Self {
Self {
global: true,
..self
}
}
pub fn with_key<Key>(self, key: Key) -> BreakpointBuilderWithKey<Key>
where
Key: KeyType,
{
BreakpointBuilderWithKey {
ctx: self.ctx,
view: self.view,
global: self.global,
key,
}
}
pub fn with_tag<Tag>(self, tag: Tag) -> BreakpointBuilderWithTag<Tag>
where
Tag: TagType,
{
BreakpointBuilderWithTag {
ctx: self.ctx,
view: self.view,
global: self.global,
tag,
}
}
}
impl<Key> BreakpointBuilderWithKey<Key>
where
Key: KeyType,
{
pub fn with_tag<Tag>(self, tag: Tag) -> BreakpointBuilderWithKeyTag<Key, Tag>
where
Tag: TagType,
{
BreakpointBuilderWithKeyTag {
ctx: self.ctx,
view: self.view,
global: self.global,
key: self.key,
tag,
}
}
}
impl<Tag> BreakpointBuilderWithTag<Tag>
where
Tag: TagType,
{
pub fn with_key<Key>(self, key: Key) -> BreakpointBuilderWithKeyTag<Key, Tag>
where
Key: KeyType,
{
BreakpointBuilderWithKeyTag {
ctx: self.ctx,
view: self.view,
global: self.global,
key,
tag: self.tag,
}
}
}
impl<Key, Tag> From<BreakpointBuilder> for Breakpoint<Key, Tag>
where
Key: KeyType + Default,
Tag: TagType + Default,
{
fn from(value: BreakpointBuilder) -> Self {
Self {
ctx: value.ctx,
view: value.view,
global: value.global,
key: Default::default(),
tag: Default::default(),
}
}
}
impl<Key, Tag> From<BreakpointBuilderWithKey<Key>> for Breakpoint<Key, Tag>
where
Key: KeyType,
Tag: TagType + Default,
{
fn from(value: BreakpointBuilderWithKey<Key>) -> Self {
Self {
ctx: value.ctx,
view: value.view,
global: value.global,
key: value.key,
tag: Default::default(),
}
}
}
impl<Key, Tag> From<BreakpointBuilderWithTag<Tag>> for Breakpoint<Key, Tag>
where
Key: KeyType + Default,
Tag: TagType,
{
fn from(value: BreakpointBuilderWithTag<Tag>) -> Self {
Self {
ctx: value.ctx,
view: value.view,
global: value.global,
key: Default::default(),
tag: value.tag,
}
}
}
impl<Key, Tag> From<BreakpointBuilderWithKeyTag<Key, Tag>> for Breakpoint<Key, Tag>
where
Key: KeyType,
Tag: TagType,
{
fn from(value: BreakpointBuilderWithKeyTag<Key, Tag>) -> Self {
Self {
ctx: value.ctx,
view: value.view,
global: value.global,
key: value.key,
tag: value.tag,
}
}
}