use std::{
fmt::{self, Debug},
io::{Read, Write},
iter::FromIterator,
slice::{Iter, IterMut},
};
use crate::{
self as neli,
attr::AttrHandle,
consts::{genl::NlAttrType, nl::NlType, rtnl::RtaType},
err::DeError,
genl::{AttrTypeBuilder, GenlAttrHandle, Nlattr, NlattrBuilder},
nl::Nlmsghdr,
rtnl::{RtAttrHandle, Rtattr},
FromBytesWithInput, Size, ToBytes,
};
#[derive(Clone, PartialEq, Eq, Size)]
pub struct Buffer(Vec<u8>);
impl FromBytesWithInput for Buffer {
type Input = usize;
fn from_bytes_with_input(
buffer: &mut std::io::Cursor<impl AsRef<[u8]>>,
input: Self::Input,
) -> Result<Self, DeError> {
if buffer.position() as usize + input > buffer.get_ref().as_ref().len() {
return Err(DeError::InvalidInput(input));
}
let mut vec = vec![0u8; input];
buffer.read_exact(&mut vec)?;
Ok(Self::from(vec))
}
}
impl ToBytes for Buffer {
fn to_bytes(&self, buffer: &mut std::io::Cursor<Vec<u8>>) -> Result<(), crate::err::SerError> {
buffer.write_all(self.0.as_slice())?;
Ok(())
}
}
impl Debug for Buffer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Buffer")
}
}
impl AsRef<[u8]> for Buffer {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
impl AsMut<[u8]> for Buffer {
fn as_mut(&mut self) -> &mut [u8] {
self.0.as_mut_slice()
}
}
impl<'a> From<&'a [u8]> for Buffer {
fn from(slice: &'a [u8]) -> Self {
Buffer(Vec::from(slice))
}
}
impl From<Vec<u8>> for Buffer {
fn from(vec: Vec<u8>) -> Self {
Buffer(vec)
}
}
impl From<Buffer> for Vec<u8> {
fn from(buf: Buffer) -> Self {
buf.0
}
}
impl Buffer {
pub fn new() -> Self {
Buffer(Vec::new())
}
pub fn extend_from_slice(&mut self, slice: &[u8]) {
self.0.extend_from_slice(slice)
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl Default for Buffer {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, PartialEq, Eq, Size, FromBytesWithInput, ToBytes)]
#[neli(from_bytes_bound = "T: NlType")]
#[neli(from_bytes_bound = "P: Size + FromBytesWithInput<Input = usize>")]
pub struct NlBuffer<T, P>(#[neli(input)] Vec<Nlmsghdr<T, P>>);
impl<T, P> FromIterator<Nlmsghdr<T, P>> for NlBuffer<T, P> {
fn from_iter<I>(i: I) -> Self
where
I: IntoIterator<Item = Nlmsghdr<T, P>>,
{
NlBuffer(Vec::from_iter(i))
}
}
impl<T, P> AsRef<[Nlmsghdr<T, P>]> for NlBuffer<T, P> {
fn as_ref(&self) -> &[Nlmsghdr<T, P>] {
self.0.as_slice()
}
}
impl<T, P> NlBuffer<T, P> {
pub fn new() -> Self {
NlBuffer(Vec::new())
}
pub fn push(&mut self, msg: Nlmsghdr<T, P>) {
self.0.push(msg);
}
pub fn pop(&mut self) -> Option<Nlmsghdr<T, P>> {
self.0.pop()
}
pub fn iter(&self) -> Iter<'_, Nlmsghdr<T, P>> {
self.0.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, Nlmsghdr<T, P>> {
self.0.iter_mut()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl<T, P> IntoIterator for NlBuffer<T, P> {
type Item = Nlmsghdr<T, P>;
type IntoIter = <Vec<Nlmsghdr<T, P>> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<T, P> Default for NlBuffer<T, P> {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, PartialEq, Eq, ToBytes, FromBytesWithInput)]
#[neli(to_bytes_bound = "T: NlAttrType")]
#[neli(from_bytes_bound = "T: NlAttrType")]
#[neli(from_bytes_bound = "P: FromBytesWithInput<Input = usize>")]
pub struct GenlBuffer<T, P>(#[neli(input)] Vec<Nlattr<T, P>>);
impl<T, P> neli::Size for GenlBuffer<T, P>
where
T: Size,
P: Size,
{
fn unpadded_size(&self) -> usize {
self.0.iter().map(|attr| attr.padded_size()).sum()
}
}
impl<T> GenlBuffer<T, Buffer> {
pub fn get_attr_handle(&self) -> AttrHandle<'_, Self, Nlattr<T, Buffer>> {
AttrHandle::new_borrowed(self.0.as_ref())
}
}
impl GenlBuffer<u16, Buffer> {
pub fn get_typed_attr_handle<T>(&self) -> Result<GenlAttrHandle<'_, T>, DeError>
where
T: NlAttrType,
{
Ok(AttrHandle::new({
let mut attrs = GenlBuffer::new();
for attr in self.0.iter() {
attrs.push(
NlattrBuilder::default()
.nla_type(
AttrTypeBuilder::default()
.nla_type(T::from(*attr.nla_type().nla_type()))
.nla_nested(*attr.nla_type().nla_nested())
.nla_network_order(*attr.nla_type().nla_network_order())
.build()?,
)
.nla_payload(attr.nla_payload().clone())
.build()?,
);
}
attrs
}))
}
}
impl<T, P> AsRef<[Nlattr<T, P>]> for GenlBuffer<T, P> {
fn as_ref(&self) -> &[Nlattr<T, P>] {
self.0.as_slice()
}
}
impl<T, P> AsMut<[Nlattr<T, P>]> for GenlBuffer<T, P> {
fn as_mut(&mut self) -> &mut [Nlattr<T, P>] {
self.0.as_mut_slice()
}
}
impl<T, P> FromIterator<Nlattr<T, P>> for GenlBuffer<T, P> {
fn from_iter<I>(i: I) -> Self
where
I: IntoIterator<Item = Nlattr<T, P>>,
{
GenlBuffer(Vec::from_iter(i))
}
}
impl<T, P> IntoIterator for GenlBuffer<T, P> {
type Item = Nlattr<T, P>;
type IntoIter = <Vec<Nlattr<T, P>> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<T, P> GenlBuffer<T, P> {
pub fn new() -> Self {
GenlBuffer(Vec::new())
}
pub fn push(&mut self, attr: Nlattr<T, P>) {
self.0.push(attr)
}
pub fn pop(&mut self) -> Option<Nlattr<T, P>> {
self.0.pop()
}
pub fn iter(&self) -> Iter<'_, Nlattr<T, P>> {
self.0.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, Nlattr<T, P>> {
self.0.iter_mut()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl<T, P> Default for GenlBuffer<T, P> {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, FromBytesWithInput, ToBytes)]
#[neli(from_bytes_bound = "T: RtaType")]
#[neli(from_bytes_bound = "P: FromBytesWithInput<Input = usize>")]
pub struct RtBuffer<T, P>(#[neli(input)] Vec<Rtattr<T, P>>);
impl<T, P> neli::Size for RtBuffer<T, P>
where
T: Size,
P: Size,
{
fn unpadded_size(&self) -> usize {
self.0.iter().map(|attr| attr.padded_size()).sum()
}
}
impl<T> RtBuffer<T, Buffer> {
pub fn get_attr_handle(&self) -> RtAttrHandle<'_, T> {
AttrHandle::new_borrowed(self.0.as_ref())
}
}
impl<T, P> FromIterator<Rtattr<T, P>> for RtBuffer<T, P> {
fn from_iter<I>(i: I) -> Self
where
I: IntoIterator<Item = Rtattr<T, P>>,
{
RtBuffer(Vec::from_iter(i))
}
}
impl<T, P> IntoIterator for RtBuffer<T, P> {
type Item = Rtattr<T, P>;
type IntoIter = <Vec<Rtattr<T, P>> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<T, P> AsRef<[Rtattr<T, P>]> for RtBuffer<T, P> {
fn as_ref(&self) -> &[Rtattr<T, P>] {
self.0.as_slice()
}
}
impl<T, P> AsMut<[Rtattr<T, P>]> for RtBuffer<T, P> {
fn as_mut(&mut self) -> &mut [Rtattr<T, P>] {
self.0.as_mut_slice()
}
}
impl<T, P> RtBuffer<T, P> {
pub fn new() -> Self {
RtBuffer(Vec::new())
}
pub fn push(&mut self, attr: Rtattr<T, P>) {
self.0.push(attr)
}
pub fn pop(&mut self) -> Option<Rtattr<T, P>> {
self.0.pop()
}
pub fn iter(&self) -> Iter<'_, Rtattr<T, P>> {
self.0.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, Rtattr<T, P>> {
self.0.iter_mut()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl<T, P> Default for RtBuffer<T, P> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{
consts::{genl::Index, rtnl::Ifa},
genl::{AttrTypeBuilder, NlattrBuilder},
rtnl::RtattrBuilder,
};
#[test]
fn test_genlbuffer_align() {
assert_eq!(
vec![
NlattrBuilder::default()
.nla_type(
AttrTypeBuilder::default()
.nla_type(Index::from(0))
.build()
.unwrap(),
)
.nla_payload(0u8)
.build()
.unwrap(),
NlattrBuilder::default()
.nla_type(
AttrTypeBuilder::default()
.nla_type(Index::from(1))
.build()
.unwrap(),
)
.nla_payload(1u8)
.build()
.unwrap(),
NlattrBuilder::default()
.nla_type(
AttrTypeBuilder::default()
.nla_type(Index::from(2))
.build()
.unwrap(),
)
.nla_payload(2u8)
.build()
.unwrap(),
]
.into_iter()
.collect::<GenlBuffer<Index, Buffer>>()
.unpadded_size(),
24
)
}
#[test]
fn test_rtbuffer_align() {
assert_eq!(
vec![
RtattrBuilder::default()
.rta_type(Ifa::Unspec)
.rta_payload(0u8)
.build()
.unwrap(),
RtattrBuilder::default()
.rta_type(Ifa::Address)
.rta_payload(1u8)
.build()
.unwrap(),
RtattrBuilder::default()
.rta_type(Ifa::Local)
.rta_payload(2u8)
.build()
.unwrap(),
]
.into_iter()
.collect::<RtBuffer<Ifa, Buffer>>()
.unpadded_size(),
24
)
}
}