1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Shared attribute code for all types of netlink attributes.
//!  
//! This module is relatively small right now and will eventually
//! contain more code once type parameters in associated
//! types defined in traits are stabilized. Due to `neli` being
//! supported on stable and nightly, I cannot currently use
//! this feature and have opted to define implementations of the
//! trait separately for [`Rtattr`][crate::rtnl::Rtattr] and
//! [`Nlattr`][crate::genl::Nlattr] types in the
//! `rtnl.rs` and `genl.rs` modules respectively.

use std::{
    io::Cursor,
    slice::{Iter, IterMut},
};

use crate::{
    err::{DeError, SerError},
    types::Buffer,
    FromBytes, FromBytesWithInput, Size, ToBytes,
};

/// Trait that defines shared operations for netlink attributes.
/// Currently, this applies to generic netlink and routing netlink
/// attributes.
pub trait Attribute<T> {
    /// Get the payload of the given attribute.
    ///
    /// Due to Rust's requirement that all elements of a [`Vec`] are of
    /// the same type, payloads are represented as a byte buffer so
    /// that nested attributes that contain multiple types for the
    /// payload can be type checked before serialization yet still
    /// contained all in the same top level attribute.
    fn payload(&self) -> &Buffer;

    /// Set the payload to a data type that implements [`ToBytes`] -
    /// this function will overwrite the current payload.
    ///
    /// This method serializes the `payload` parameter and stores
    /// the resulting byte buffer as the payload.
    fn set_payload<P>(&mut self, payload: &P) -> Result<(), SerError>
    where
        P: Size + ToBytes;

    /// Get an [`Nlattr`][crate::genl::Nlattr] payload as the
    /// provided type parameter, `R`.
    fn get_payload_as<'a, R>(&'a self) -> Result<R, DeError>
    where
        R: FromBytes<'a>,
    {
        R::from_bytes(&mut Cursor::new(self.payload().as_ref()))
    }

    /// Get an [`Nlattr`][crate::genl::Nlattr] payload as the
    /// provided type parameter, `R`.
    fn get_payload_as_with_len<'a, R>(&'a self) -> Result<R, DeError>
    where
        R: FromBytesWithInput<'a, Input = usize>,
    {
        R::from_bytes_with_input(
            &mut Cursor::new(self.payload().as_ref()),
            self.payload().len(),
        )
    }
}

/// Handle returned for traversing nested attribute structures
pub enum AttrHandle<'a, O, I> {
    /// Owned vector
    Owned(O),
    /// Vector reference
    Borrowed(&'a [I]),
}

impl<'a, O, I> AttrHandle<'a, O, I>
where
    O: AsRef<[I]>,
{
    /// Create new [`AttrHandle`]
    pub fn new(owned: O) -> Self {
        AttrHandle::Owned(owned)
    }

    /// Create new borrowed [`AttrHandle`]
    pub fn new_borrowed(borrowed: &'a [I]) -> Self {
        AttrHandle::Borrowed(borrowed)
    }

    /// Pass back iterator over attributes
    pub fn iter(&self) -> Iter<I> {
        self.get_attrs().iter()
    }

    /// Get the underlying owned value as a reference
    pub fn get_attrs(&self) -> &[I] {
        match *self {
            AttrHandle::Owned(ref o) => o.as_ref(),
            AttrHandle::Borrowed(b) => b,
        }
    }
}

/// Handle for traversing nested attribute structures mutably
pub enum AttrHandleMut<'a, O, I> {
    /// Owned vector
    Owned(O),
    /// Vector reference
    Borrowed(&'a mut [I]),
}

impl<'a, O, I> AttrHandleMut<'a, O, I>
where
    O: AsRef<[I]> + AsMut<[I]>,
{
    /// Create new `AttrHandle`
    pub fn new(owned: O) -> Self {
        AttrHandleMut::Owned(owned)
    }

    /// Create new borrowed [`AttrHandleMut`]
    pub fn new_borrowed(borrowed: &'a mut [I]) -> Self {
        AttrHandleMut::Borrowed(borrowed)
    }

    /// Pass back iterator over attributes
    pub fn iter_mut(&mut self) -> IterMut<I> {
        self.get_mut_attrs().iter_mut()
    }

    /// Get the underlying owned value as a mutable reference or
    /// return [`None`].
    pub fn get_mut_attrs(&mut self) -> &mut [I] {
        match self {
            AttrHandleMut::Owned(ref mut o) => o.as_mut(),
            AttrHandleMut::Borrowed(b) => b,
        }
    }
}