nell 0.3.0

Linux netlink interface
Documentation
// Copyright (C) 2020 - Will Glozer. All rights reserved.

use std::convert::TryFrom;
use std::mem::size_of;
use std::os::raw::c_int;
use std::slice;
use crate::ffi::nlattr;
use crate::sys::{align, Bytes};
use super::{Buffer, Error};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Attr<'a> {
    kind:  u16,
    value: Value<'a>
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Value<'a> {
    AsciiZ(&'a str),
    Bytes(&'a [u8]),
    Number(Number),
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Number {
    U8 (u8 ),
    U16(u16),
    U32(u32),
    CInt(c_int),
}

impl<'a> Attr<'a> {
    pub fn write(&self, buf: &mut Buffer<'_>) -> Result<(), Error> {
        let n = self.value.size();
        buf.write(&nlattr {
            nla_len:  nla_len(n)?,
            nla_type: self.kind,
        })?;
        let buffer = buf.buffer(n)?;
        let buffer = &mut buffer[..n];
        self.value.write(buffer)?;
        Ok(())
    }
}

impl<'a> Value<'a> {
    fn write(&self, buf: &mut [u8]) -> Result<(), Error> {
        match self {
            Self::AsciiZ(v) => v.write(buf),
            Self::Bytes(v)  => v.write(buf),
            Self::Number(v) => v.write(buf),
        }
        Ok(())
    }

    fn size(&self) -> usize {
        match self {
            Self::AsciiZ(v) => v.len() + 1,
            Self::Bytes(v)  => v.len(),
            Self::Number(v) => v.size(),
        }
    }
}

impl Number {
    fn size(self) -> usize {
        match self {
            Self::U8(_)   => size_of::<u8>(),
            Self::U16(_)  => size_of::<u16>(),
            Self::U32(_)  => size_of::<u32>(),
            Self::CInt(_) => size_of::<c_int>(),
        }
    }
}

pub fn attr<'a, T: Into<Value<'a>>>(kind: u16, value: T) -> Attr<'a> {
    Attr::from((kind, value.into()))
}

impl<'a> From<(u16, Value<'a>)> for Attr<'a> {
    fn from((kind, value): (u16, Value<'a>)) -> Self {
        Self {
            kind:  kind,
            value: value,
        }
    }
}

impl<'a> From<&'a str> for Value<'a> {
    fn from(v: &'a str) -> Self {
        Self::AsciiZ(v)
    }
}

impl<'a> From<&'a [u8]> for Value<'a> {
    fn from(v: &'a [u8]) -> Self {
        Self::Bytes(v)
    }
}

impl<'a, T: Bytes> From<&'a T> for Value<'a> {
    fn from(v: &'a T) -> Self {
        Self::Bytes(unsafe {
            let ptr = v as *const T as *const u8;
            let len = size_of::<T>();
            slice::from_raw_parts(ptr, len)
        })
    }
}

impl<'a> From<u8> for Value<'a> {
    fn from(v: u8) -> Self {
        Self::Number(Number::U8(v))
    }
}

impl<'a> From<u16> for Value<'a> {
    fn from(v: u16) -> Self {
        Self::Number(Number::U16(v))
    }
}

impl<'a> From<u32> for Value<'a> {
    fn from(v: u32) -> Self {
        Self::Number(Number::U32(v))
    }
}

impl<'a> From<c_int> for Value<'a> {
    fn from(v: c_int) -> Self {
        Self::Number(Number::CInt(v))
    }
}

trait Write {
    fn write(&self, buf: &mut [u8]);
}

impl Write for Number {
    fn write(&self, buf: &mut [u8]) {
        match self {
            Self::U8 (n)  => buf.copy_from_slice(&[*n]),
            Self::U16(n)  => buf.copy_from_slice(&n.to_le_bytes()),
            Self::U32(n)  => buf.copy_from_slice(&n.to_le_bytes()),
            Self::CInt(n) => buf.copy_from_slice(&n.to_le_bytes()),
        }
    }
}

impl Write for &str {
    fn write(&self, buf: &mut [u8]) {
        let bytes = self.as_bytes();
        let n = bytes.len();
        let (s, z) = buf.split_at_mut(n);
        s.copy_from_slice(bytes);
        z.copy_from_slice(&[0]);
    }
}

impl Write for &[u8] {
    fn write(&self, buf: &mut [u8]) {
        buf.copy_from_slice(self);
    }
}

fn nla_len(size: usize) -> Result<u16, Error> {
    let head = align(size_of::<nlattr>());
    let size = head.saturating_add(size);
    Ok(u16::try_from(size)?)
 }