use crate::{
extract::{transmute_field, Extract},
Event, StateChange, TryExtract,
};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::mem;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "strum")]
use strum::{Display, EnumCount, EnumIter, IntoStaticStr, VariantNames};
pub use windows_core::GUID;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ContentGUID {
pub content_id: u32,
#[cfg_attr(feature = "serde", serde(with = "crate::serde_guid"))]
pub guid: GUID,
pub content_local: Option<ContentLocal>,
}
impl ContentGUID {
#[inline]
pub fn guid_string(&self) -> String {
self.guid.format_simple()
}
#[inline]
pub fn is_effect(&self) -> bool {
matches!(self.content_local, Some(ContentLocal::Effect))
}
#[inline]
pub fn is_marker(&self) -> bool {
matches!(self.content_local, Some(ContentLocal::Marker))
}
}
impl Extract for ContentGUID {
#[inline]
unsafe fn extract(event: &Event) -> Self {
Self {
content_id: event.skill_id,
guid: transmute_field!(event.src_agent as GUID),
content_local: event.overstack_value.try_into().ok(),
}
}
}
impl TryExtract for ContentGUID {
#[inline]
fn can_extract(event: &Event) -> bool {
event.get_statechange() == StateChange::IdToGUID
}
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, IntoPrimitive, TryFromPrimitive,
)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "strum",
derive(Display, EnumCount, EnumIter, IntoStaticStr, VariantNames)
)]
#[repr(u32)]
pub enum ContentLocal {
Effect = 0,
Marker = 1,
}
pub trait GuidExt {
fn format_simple(&self) -> String;
fn format_hyphenated(&self) -> String;
unsafe fn misinterpret(&self) -> [u8; 16];
}
impl GuidExt for GUID {
#[inline]
fn format_simple(&self) -> String {
format!("{:0>32X}", self.to_u128())
}
#[inline]
fn format_hyphenated(&self) -> String {
format!("{self:?}")
}
#[inline]
unsafe fn misinterpret(&self) -> [u8; 16] {
mem::transmute::<GUID, [u8; 16]>(*self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem;
#[test]
fn extract() {
let event = Event {
is_statechange: StateChange::IdToGUID.into(),
src_agent: 4820869827943421467,
dst_agent: 11091919494850445953,
skill_id: 446,
overstack_value: 0,
..unsafe { mem::zeroed() }
};
assert_eq!(event.src_agent, 0x42E72B9102F7561B);
assert_eq!(event.dst_agent, 0x99EE6A0357CA8281);
let info = ContentGUID::try_extract(&event).expect("failed to extract");
assert_eq!(
info.guid,
GUID::from_u128(0x02F7561B_2B91_42E7_8182_CA57036AEE99)
);
}
#[test]
fn guid_format() {
let guid = GUID::from_u128(0x02F7561B_2B91_42E7_8182_CA57036AEE99);
assert_eq!(guid.format_simple(), "02F7561B2B9142E78182CA57036AEE99");
assert_eq!(
guid.format_hyphenated(),
"02F7561B-2B91-42E7-8182-CA57036AEE99"
);
}
}