#![deny(missing_docs)]
pub mod attr;
pub mod consts;
pub mod err;
pub mod genl;
pub mod iter;
pub mod nl;
pub mod router;
pub mod rtnl;
pub mod socket;
pub mod types;
pub mod utils;
use std::{
fmt::Debug,
io::{Cursor, Read, Write},
marker::PhantomData,
str,
};
use byteorder::{BigEndian, NativeEndian, ReadBytesExt};
pub use neli_proc_macros::{neli_enum, FromBytes, FromBytesWithInput, Header, Size, ToBytes};
use crate::{
self as neli,
consts::alignto,
err::{DeError, SerError},
};
pub trait Size {
fn unpadded_size(&self) -> usize;
fn padded_size(&self) -> usize {
alignto(self.unpadded_size())
}
}
pub trait TypeSize {
fn type_size() -> usize;
}
pub trait ToBytes: Debug {
fn to_bytes(&self, buffer: &mut Cursor<Vec<u8>>) -> Result<(), SerError>;
fn pad(&self, buffer: &mut Cursor<Vec<u8>>) -> Result<(), SerError> {
let num_pad_bytes = alignto(buffer.position() as usize) - buffer.position() as usize;
buffer.write_all(&[0; libc::NLA_ALIGNTO as usize][..num_pad_bytes])?;
Ok(())
}
}
pub trait FromBytes: Sized + Debug {
fn from_bytes(buffer: &mut Cursor<impl AsRef<[u8]>>) -> Result<Self, DeError>;
fn strip(buffer: &mut Cursor<impl AsRef<[u8]>>) -> Result<(), DeError> {
let num_strip_bytes = alignto(buffer.position() as usize) - buffer.position() as usize;
buffer.read_exact(&mut [0; libc::NLA_ALIGNTO as usize][..num_strip_bytes])?;
Ok(())
}
}
pub trait FromBytesWithInput: Sized + Debug {
type Input: Debug;
fn from_bytes_with_input(
buffer: &mut Cursor<impl AsRef<[u8]>>,
input: Self::Input,
) -> Result<Self, DeError>;
fn strip(buffer: &mut Cursor<impl AsRef<[u8]>>) -> Result<(), DeError> {
let num_strip_bytes = alignto(buffer.position() as usize) - buffer.position() as usize;
buffer.read_exact(&mut [0; libc::NLA_ALIGNTO as usize][..num_strip_bytes])?;
Ok(())
}
}
pub trait FromBytesWithInputBorrowed<'a>: Sized + Debug {
type Input: Debug;
fn from_bytes_with_input(
buffer: &mut Cursor<&'a [u8]>,
input: Self::Input,
) -> Result<Self, DeError>;
fn strip(buffer: &mut Cursor<&'a [u8]>) -> Result<(), DeError> {
let num_strip_bytes = alignto(buffer.position() as usize) - buffer.position() as usize;
buffer.read_exact(&mut [0; libc::NLA_ALIGNTO as usize][..num_strip_bytes])?;
Ok(())
}
}
pub trait Header {
fn header_size() -> usize;
}
macro_rules! impl_nl_int {
(impl__ $ty:ty) => {
impl $crate::Size for $ty {
fn unpadded_size(&self) -> usize {
std::mem::size_of::<$ty>()
}
}
impl $crate::TypeSize for $ty {
fn type_size() -> usize {
std::mem::size_of::<$ty>()
}
}
};
($ty:ty, $read_method:ident, $write_method:ident) => {
impl_nl_int!(impl__ $ty);
impl $crate::ToBytes for $ty {
fn to_bytes(&self, buffer: &mut std::io::Cursor<Vec<u8>>) -> Result<(), $crate::err::SerError> {
<std::io::Cursor::<Vec<u8>> as byteorder::WriteBytesExt>::$write_method(buffer, *self)?;
Ok(())
}
}
impl $crate::FromBytes for $ty {
fn from_bytes(buffer: &mut std::io::Cursor<impl AsRef<[u8]>>) -> Result<Self, $crate::err::DeError> {
Ok(<std::io::Cursor<_> as byteorder::ReadBytesExt>::$read_method(buffer)?)
}
}
};
($ty:ty, $read_method:ident, $write_method:ident, $endianness:ty) => {
impl_nl_int!(impl__ $ty);
impl $crate::ToBytes for $ty {
fn to_bytes(&self, buffer: &mut std::io::Cursor<Vec<u8>>) -> Result<(), $crate::err::SerError> {
<std::io::Cursor::<Vec<u8>> as byteorder::WriteBytesExt>::$write_method::<$endianness>(buffer, *self)?;
Ok(())
}
}
impl $crate::FromBytes for $ty {
fn from_bytes(buffer: &mut std::io::Cursor<impl AsRef<[u8]>>) -> Result<Self, $crate::err::DeError> {
Ok(<std::io::Cursor<_> as byteorder::ReadBytesExt>::$read_method::<$endianness>(buffer)?)
}
}
}
}
impl_nl_int!(u8, read_u8, write_u8);
impl_nl_int!(u16, read_u16, write_u16, NativeEndian);
impl_nl_int!(u32, read_u32, write_u32, NativeEndian);
impl_nl_int!(u64, read_u64, write_u64, NativeEndian);
impl_nl_int!(u128, read_u128, write_u128, NativeEndian);
impl_nl_int!(i8, read_i8, write_i8);
impl_nl_int!(i16, read_i16, write_i16, NativeEndian);
impl_nl_int!(i32, read_i32, write_i32, NativeEndian);
impl_nl_int!(i64, read_i64, write_i64, NativeEndian);
impl_nl_int!(i128, read_i128, write_i128, NativeEndian);
impl_nl_int!(f32, read_f32, write_f32, NativeEndian);
impl_nl_int!(f64, read_f64, write_f64, NativeEndian);
impl Size for () {
fn unpadded_size(&self) -> usize {
0
}
}
impl ToBytes for () {
fn to_bytes(&self, _: &mut Cursor<Vec<u8>>) -> Result<(), SerError> {
Ok(())
}
}
impl FromBytes for () {
fn from_bytes(_: &mut Cursor<impl AsRef<[u8]>>) -> Result<Self, DeError> {
Ok(())
}
}
impl FromBytesWithInput for () {
type Input = usize;
fn from_bytes_with_input(
_: &mut Cursor<impl AsRef<[u8]>>,
input: usize,
) -> Result<Self, DeError> {
assert_eq!(input, 0);
Ok(())
}
}
impl<T> Size for PhantomData<T> {
fn unpadded_size(&self) -> usize {
0
}
}
impl<T> TypeSize for PhantomData<T> {
fn type_size() -> usize {
0
}
}
impl<T> ToBytes for PhantomData<T> {
fn to_bytes(&self, _: &mut Cursor<Vec<u8>>) -> Result<(), SerError> {
Ok(())
}
}
impl<T> FromBytes for PhantomData<T> {
fn from_bytes(_: &mut Cursor<impl AsRef<[u8]>>) -> Result<Self, DeError> {
Ok(PhantomData)
}
}
impl<'a> Size for &'a str {
fn unpadded_size(&self) -> usize {
self.len() + 1
}
}
impl<'a> ToBytes for &'a str {
fn to_bytes(&self, buffer: &mut Cursor<Vec<u8>>) -> Result<(), SerError> {
buffer.write_all(self.as_bytes())?;
buffer.write_all(&[0])?;
Ok(())
}
}
impl<'a> FromBytesWithInputBorrowed<'a> for &'a str {
type Input = usize;
fn from_bytes_with_input(buffer: &mut Cursor<&'a [u8]>, input: usize) -> Result<Self, DeError> {
let position = buffer.position() as usize;
Ok(str::from_utf8(
&buffer.get_ref()[position..position + input],
)?)
}
}
impl Size for String {
fn unpadded_size(&self) -> usize {
self.as_str().unpadded_size()
}
}
impl ToBytes for String {
fn to_bytes(&self, buffer: &mut Cursor<Vec<u8>>) -> Result<(), SerError> {
self.as_str().to_bytes(buffer)?;
Ok(())
}
}
impl FromBytesWithInput for String {
type Input = usize;
fn from_bytes_with_input(
buffer: &mut Cursor<impl AsRef<[u8]>>,
input: usize,
) -> Result<Self, DeError> {
let s = String::from_utf8(
buffer.get_ref().as_ref()
[buffer.position() as usize..buffer.position() as usize + input - 1]
.to_vec(),
)?;
buffer.set_position(buffer.position() + input as u64);
Ok(s)
}
}
impl<'a> Size for &'a [u8] {
fn unpadded_size(&self) -> usize {
self.len()
}
}
impl<'a> ToBytes for &'a [u8] {
fn to_bytes(&self, buffer: &mut Cursor<Vec<u8>>) -> Result<(), SerError> {
buffer.write_all(self)?;
Ok(())
}
}
impl<'a> FromBytesWithInputBorrowed<'a> for &'a [u8] {
type Input = usize;
fn from_bytes_with_input(buffer: &mut Cursor<&'a [u8]>, input: usize) -> Result<Self, DeError> {
let position = buffer.position() as usize;
Ok(&buffer.get_ref()[position..position + input])
}
}
impl<T> Size for Vec<T>
where
T: Size,
{
fn unpadded_size(&self) -> usize {
self.iter()
.fold(0, |count, elem| count + elem.unpadded_size())
}
}
impl<T> ToBytes for Vec<T>
where
T: ToBytes,
{
fn to_bytes(&self, buffer: &mut Cursor<Vec<u8>>) -> Result<(), SerError> {
for elem in self.iter() {
elem.to_bytes(buffer)?;
}
Ok(())
}
}
impl<T> FromBytesWithInput for Vec<T>
where
T: FromBytes,
{
type Input = usize;
fn from_bytes_with_input(
buffer: &mut 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::new();
let orig_pos = buffer.position();
loop {
if buffer.position() as usize == orig_pos as usize + input {
break;
}
match T::from_bytes(buffer) {
Ok(elem) => vec.push(elem),
Err(e) => {
buffer.set_position(orig_pos);
return Err(e);
}
}
if buffer.position() as usize > orig_pos as usize + input {
buffer.set_position(orig_pos);
return Err(DeError::InvalidInput(input));
}
}
Ok(vec)
}
}
#[derive(Copy, Debug, Clone, PartialEq, Eq, Size)]
pub struct BeU64(u64);
impl BeU64 {
pub fn new(v: u64) -> Self {
BeU64(v)
}
pub fn as_ne_u64(self) -> u64 {
self.0
}
}
impl ToBytes for BeU64 {
fn to_bytes(&self, buffer: &mut Cursor<Vec<u8>>) -> Result<(), SerError> {
buffer.write_all(&self.0.to_be_bytes() as &[u8])?;
Ok(())
}
}
impl FromBytes for BeU64 {
fn from_bytes(buffer: &mut Cursor<impl AsRef<[u8]>>) -> Result<Self, DeError> {
Ok(BeU64(buffer.read_u64::<BigEndian>()?))
}
}
#[cfg(test)]
fn serialize<T>(t: &T) -> Result<Vec<u8>, SerError>
where
T: ToBytes,
{
let mut buffer = Cursor::new(Vec::new());
t.to_bytes(&mut buffer)?;
Ok(buffer.into_inner())
}
#[cfg(test)]
mod test {
use super::*;
use env_logger::init;
use lazy_static::lazy_static;
lazy_static! {
static ref LOGGER: () = init();
}
#[allow(clippy::no_effect)]
pub fn setup() {
*LOGGER;
}
#[test]
fn test_nl_u8() {
setup();
let v = 5u8;
let ser_buffer = serialize(&v).unwrap();
assert_eq!(ser_buffer.as_slice()[0], v);
let de = u8::from_bytes(&mut Cursor::new(&[5u8] as &[u8])).unwrap();
assert_eq!(de, 5)
}
#[test]
fn test_nl_u16() {
setup();
let v = 6000u16;
let desired_buffer = v.to_ne_bytes();
let ser_buffer = serialize(&v).unwrap();
assert_eq!(ser_buffer.as_slice(), &desired_buffer);
let de = u16::from_bytes(&mut Cursor::new(&v.to_ne_bytes() as &[u8])).unwrap();
assert_eq!(de, 6000);
}
#[test]
fn test_nl_i32() {
setup();
let v = 600_000i32;
let desired_buffer = v.to_ne_bytes();
let ser_buffer = serialize(&v).unwrap();
assert_eq!(ser_buffer.as_slice(), &desired_buffer);
let de = i32::from_bytes(&mut Cursor::new(&v.to_ne_bytes() as &[u8])).unwrap();
assert_eq!(de, 600_000);
let v = -600_000i32;
let desired_buffer = v.to_ne_bytes();
let ser_buffer = serialize(&v).unwrap();
assert_eq!(ser_buffer.as_slice(), &desired_buffer);
let de = i32::from_bytes(&mut Cursor::new(&v.to_ne_bytes() as &[u8])).unwrap();
assert_eq!(de, -600_000)
}
#[test]
fn test_nl_u32() {
setup();
let v = 600_000u32;
let desired_buffer = v.to_ne_bytes();
let ser_buffer = serialize(&v).unwrap();
assert_eq!(ser_buffer.as_slice(), &desired_buffer);
let de = u32::from_bytes(&mut Cursor::new(&v.to_ne_bytes() as &[u8])).unwrap();
assert_eq!(de, 600_000)
}
#[test]
fn test_nl_u64() {
setup();
let v = 12_345_678_901_234u64;
let desired_buffer = v.to_ne_bytes();
let ser_buffer = serialize(&v).unwrap();
assert_eq!(ser_buffer.as_slice(), &desired_buffer);
let de = u64::from_bytes(&mut Cursor::new(&v.to_ne_bytes() as &[u8])).unwrap();
assert_eq!(de, 12_345_678_901_234);
}
#[test]
fn test_nl_u128() {
setup();
let v = 123_456_789_012_345_678_901_234_567_890_123_456_789u128;
let desired_buffer = v.to_ne_bytes();
let ser_buffer = serialize(&v).unwrap();
assert_eq!(ser_buffer.as_slice(), &desired_buffer);
let de = u128::from_bytes(&mut Cursor::new(&v.to_ne_bytes() as &[u8])).unwrap();
assert_eq!(de, 123_456_789_012_345_678_901_234_567_890_123_456_789);
}
#[test]
fn test_nl_be_u64() {
setup();
let v = 571_987_654u64;
let desired_buffer = v.to_be_bytes();
let ser_buffer = serialize(&BeU64(v)).unwrap();
assert_eq!(ser_buffer.as_slice(), &desired_buffer);
let de = BeU64::from_bytes(&mut Cursor::new(&v.to_be_bytes() as &[u8])).unwrap();
assert_eq!(de, BeU64(571_987_654));
}
#[test]
fn test_nl_vec() {
setup();
let vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let ser_buffer = serialize(&vec).unwrap();
assert_eq!(vec.as_slice(), ser_buffer.as_slice());
let v: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let de = Vec::<u8>::from_bytes_with_input(&mut Cursor::new(v), 9).unwrap();
assert_eq!(vec, de.as_slice());
}
#[test]
fn test_nl_string() {
setup();
let s = "AAAAA".to_string();
let desired_s = "AAAAA\0";
let ser_buffer = serialize(&s).unwrap();
assert_eq!(desired_s.as_bytes(), ser_buffer.as_slice());
let de_s = "AAAAA".to_string();
let de = String::from_bytes_with_input(&mut Cursor::new(desired_s.as_bytes()), 6).unwrap();
assert_eq!(de_s, de)
}
}