use std::sync::Arc;
use crate::{
metadata::{
tables::{
EventList, EventMap, EventMapEntry, EventMapEntryRc, EventPtrMap, MetadataTable,
TableId, TableInfoRef, TableRow,
},
token::Token,
typesystem::TypeRegistry,
},
Result,
};
#[derive(Clone, Debug)]
pub struct EventMapRaw {
pub rid: u32,
pub token: Token,
pub offset: usize,
pub parent: u32,
pub event_list: u32,
}
impl EventMapRaw {
fn resolve_event_list(
&self,
events: &EventMap,
event_ptr: &EventPtrMap,
map: &MetadataTable<EventMapRaw>,
) -> Result<EventList> {
if self.event_list == 0 || events.is_empty() {
return Ok(Arc::new(boxcar::Vec::new()));
}
let next_row_id = self.rid + 1;
let start = self.event_list as usize;
let end = if next_row_id > map.row_count {
events.len() + 1
} else {
match map.get(next_row_id) {
Some(next_row) => next_row.event_list as usize,
None => {
return Err(malformed_error!(
"Failed to resolve event_end from next row - {}",
next_row_id
))
}
}
};
if start > events.len() || end > (events.len() + 1) || end < start {
return Ok(Arc::new(boxcar::Vec::new()));
}
let event_list = Arc::new(boxcar::Vec::with_capacity(end - start));
for counter in start..end {
let actual_event_token = if event_ptr.is_empty() {
let token_value = counter | 0x1400_0000;
Token::new(u32::try_from(token_value).map_err(|_| {
malformed_error!("Token value {} exceeds u32 range", token_value)
})?)
} else {
let event_ptr_token_value = u32::try_from(counter | 0x0D00_0000).map_err(|_| {
malformed_error!("EventPtr token value too large: {}", counter | 0x0D00_0000)
})?;
let event_ptr_token = Token::new(event_ptr_token_value);
match event_ptr.get(&event_ptr_token) {
Some(event_ptr_entry) => {
let actual_event_rid = event_ptr_entry.value().event;
let actual_event_token_value = u32::try_from(
actual_event_rid as usize | 0x1400_0000,
)
.map_err(|_| {
malformed_error!(
"Event token value too large: {}",
actual_event_rid as usize | 0x1400_0000
)
})?;
Token::new(actual_event_token_value)
}
None => {
return Err(malformed_error!(
"Failed to resolve EventPtr - {}",
counter | 0x0D00_0000
))
}
}
};
match events.get(&actual_event_token) {
Some(event) => _ = event_list.push(event.value().clone()),
None => {
return Err(malformed_error!(
"Failed to resolve event - {}",
actual_event_token.value()
))
}
}
}
Ok(event_list)
}
pub fn to_owned(
&self,
types: &TypeRegistry,
events: &EventMap,
event_ptr: &EventPtrMap,
map: &MetadataTable<EventMapRaw>,
) -> Result<EventMapEntryRc> {
let parent = match types.get(&Token::new(self.parent | 0x0200_0000)) {
Some(parent_type) => parent_type.into(),
None => {
return Err(malformed_error!(
"Failed to resolve parent type - {}",
self.parent | 0x0200_0000
))
}
};
Ok(Arc::new(EventMapEntry {
rid: self.rid,
token: self.token,
offset: self.offset,
parent,
events: self.resolve_event_list(events, event_ptr, map)?,
}))
}
pub fn apply(
&self,
types: &TypeRegistry,
events: &EventMap,
event_ptr: &EventPtrMap,
map: &MetadataTable<EventMapRaw>,
) -> Result<()> {
let event_list = self.resolve_event_list(events, event_ptr, map)?;
if event_list.is_empty() && (self.event_list != 0 && !events.is_empty()) {
return Err(malformed_error!("Invalid event list"));
}
match types.get(&Token::new(self.parent | 0x0200_0000)) {
Some(event_parent) => {
for (_, entry) in event_list.iter() {
_ = event_parent.events.push(entry.clone());
}
Ok(())
}
None => Err(malformed_error!(
"Invalid parent token - {}",
self.parent | 0x0200_0000
)),
}
}
}
impl TableRow for EventMapRaw {
#[rustfmt::skip]
fn row_size(sizes: &TableInfoRef) -> u32 {
u32::from(
sizes.table_index_bytes(TableId::TypeDef) +
sizes.table_index_bytes(TableId::Event)
)
}
}