use super::{instruction::Dialect, Instruction};
use core::{fmt, mem::size_of};
use libc::sock_fprog;
use std::{io, os::fd::AsRawFd};
pub struct Program<'a, D: Dialect> {
instructions: &'a [Instruction<D>],
}
impl<'a, D: Dialect> Program<'a, D> {
#[inline]
pub const fn new(instructions: &'a [Instruction<D>]) -> Self {
if instructions.len() > D::MAX_INSTRUCTIONS {
panic!("program too large");
}
Self { instructions }
}
#[inline]
pub fn attach<S: AsRawFd>(&self, socket: &S) -> io::Result<()> {
let prog = sock_fprog {
filter: self.instructions.as_ptr() as *const _ as *mut _,
len: self.instructions.len() as _,
};
let ret = unsafe {
libc::setsockopt(
socket.as_raw_fd(),
libc::SOL_SOCKET,
D::SOCKOPT as _,
&prog as *const _ as *const _,
size_of::<sock_fprog>() as _,
)
};
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
}
}
impl<D: Dialect> fmt::Debug for Program<'_, D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Program")
.field("instructions", &self.instructions)
.finish()
}
}
impl<D: Dialect> fmt::Display for Program<'_, D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (idx, inst) in self.instructions.iter().enumerate() {
D::display(inst, f, Some(idx))?;
writeln!(f)?;
}
Ok(())
}
}