use crate::HeaderTagType;
use crate::{HeaderTagFlag, MbiTagType};
use core::fmt;
use core::fmt::{Debug, Formatter};
use core::marker::PhantomData;
use core::mem::size_of;
#[derive(Copy, Clone)]
#[repr(C)]
pub struct InformationRequestHeaderTag<const N: usize> {
typ: HeaderTagType,
flags: HeaderTagFlag,
size: u32,
requests: [MbiTagType; N],
}
impl<const N: usize> InformationRequestHeaderTag<N> {
pub fn new(flags: HeaderTagFlag, requests: [MbiTagType; N], size: Option<u32>) -> Self {
InformationRequestHeaderTag {
typ: HeaderTagType::InformationRequest,
flags,
size: size.unwrap_or(size_of::<Self>() as u32),
requests,
}
}
pub const fn typ(&self) -> HeaderTagType {
self.typ
}
pub const fn flags(&self) -> HeaderTagFlag {
self.flags
}
pub const fn size(&self) -> u32 {
self.size
}
pub const fn requests(&self) -> [MbiTagType; N] {
self.requests
}
pub const fn dynamic_requests_size(&self) -> u32 {
let base_struct_size = size_of::<InformationRequestHeaderTag<0>>();
let size_diff = self.size - base_struct_size as u32;
if size_diff > 0 {
size_diff / size_of::<u32>() as u32
} else {
0
}
}
pub fn req_iter(&self) -> InformationRequestHeaderTagIter {
let base_struct_size = size_of::<InformationRequestHeaderTag<0>>();
let count = self.dynamic_requests_size();
let base_ptr = self as *const InformationRequestHeaderTag<N>;
let base_ptr = base_ptr as *const u8;
let base_ptr = unsafe { base_ptr.add(base_struct_size) };
let base_ptr = base_ptr as *const MbiTagType;
InformationRequestHeaderTagIter::new(count, base_ptr)
}
}
impl<const N: usize> Debug for InformationRequestHeaderTag<N> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("InformationRequestHeaderTag")
.field("type", &{ self.typ })
.field("flags", &{ self.flags })
.field("size", &{ self.size })
.field("requests", &{ self.req_iter() })
.finish()
}
}
#[derive(Copy, Clone)]
pub struct InformationRequestHeaderTagIter<'a> {
base_ptr: *const MbiTagType,
i: u32,
count: u32,
_marker: PhantomData<&'a ()>,
}
impl<'a> InformationRequestHeaderTagIter<'a> {
fn new(count: u32, base_ptr: *const MbiTagType) -> Self {
Self {
i: 0,
count,
base_ptr,
_marker: PhantomData::default(),
}
}
}
impl<'a> Iterator for InformationRequestHeaderTagIter<'a> {
type Item = &'a MbiTagType;
fn next(&mut self) -> Option<Self::Item> {
if self.i < self.count {
let ptr = unsafe { self.base_ptr.offset(self.i as isize) };
self.i += 1;
Some(unsafe { &*ptr })
} else {
None
}
}
}
impl<'a> Debug for InformationRequestHeaderTagIter<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut debug = f.debug_list();
(*self).for_each(|e| {
debug.entry(e);
});
debug.finish()
}
}
#[cfg(test)]
mod tests {
use crate::InformationRequestHeaderTag;
#[test]
fn test_assert_size() {
assert_eq!(
core::mem::size_of::<InformationRequestHeaderTag<0>>(),
2 + 2 + 4 + 0 * 4
);
assert_eq!(
core::mem::size_of::<InformationRequestHeaderTag<1>>(),
2 + 2 + 4 + 1 * 4
);
assert_eq!(
core::mem::size_of::<InformationRequestHeaderTag<2>>(),
2 + 2 + 4 + 2 * 4
);
}
}