rexsgdata 0.12.0

Scatter-Gather Data Descriptors
Documentation
//
// Copyright (c) 2019 RepliXio Ltd. All rights reserved.
// Use is subject to license terms.
//

use std::fmt;
use std::ops;
use std::slice;

use libc::{c_void, iovec, size_t};
use serde::de::{self, Error};
use serde::{Serialize, Serializer};

use super::utils;

/// Intermediate element that can represent either regular `iovec` or a sequence of zeroes
#[derive(Clone)]
pub struct Iovec(iovec);

impl Iovec {
    pub(crate) fn from_slice(buf: &[u8]) -> Self {
        let iov_len = buf.len();
        let iov_base = buf.as_ptr() as *mut c_void;
        let iov = iovec { iov_base, iov_len };
        iov.into()
    }

    pub(crate) fn from_slice_mut(buf: &mut [u8]) -> Self {
        let iov_len = buf.len();
        let iov_base = buf.as_mut_ptr() as *mut c_void;
        let iov = iovec { iov_base, iov_len };
        iov.into()
    }

    /// Get a view of an `Element` as a vector of slices
    pub fn as_slice(&self) -> &[u8] {
        unsafe { utils::iovec_as_slice(&self.0) }
    }

    pub fn as_static_slice(&self) -> &'static [u8] {
        unsafe { utils::iovec_as_static_slice(self.0) }
    }

    pub fn as_iovec_mut(&self) -> iovec {
        self.0
    }
}

impl From<iovec> for Iovec {
    #[inline]
    fn from(iov: iovec) -> Self {
        Self { 0: iov }
    }
}

impl From<(*mut c_void, size_t)> for Iovec {
    fn from((iov_base, iov_len): (*mut c_void, size_t)) -> Self {
        iovec { iov_base, iov_len }.into()
    }
}

impl<'a> From<&'a [u8]> for Iovec {
    fn from(buf: &[u8]) -> Self {
        Self::from_slice(buf)
    }
}

impl<'a> From<&'a mut [u8]> for Iovec {
    fn from(buf: &mut [u8]) -> Self {
        Self::from_slice_mut(buf)
    }
}

impl fmt::Debug for Iovec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let iov = self.0;
        f.debug_struct("Element::Iovec")
            .field("iov_base", &iov.iov_base)
            .field("iov_len", &iov.iov_len)
            .finish()
    }
}

impl PartialEq for Iovec {
    fn eq(&self, other: &Self) -> bool {
        let (iov1, iov2) = (self.0, other.0);
        iov1.iov_base == iov2.iov_base && iov1.iov_len == iov2.iov_len
    }
}

impl ops::Deref for Iovec {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        self.as_slice()
    }
}

unsafe impl Send for Iovec {}
unsafe impl Sync for Iovec {}

impl Serialize for Iovec {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let iov = self.0;
        let buf = unsafe {
            let base = iov.iov_base as *const u8;
            let len = iov.iov_len as usize;
            slice::from_raw_parts(base, len)
        };
        serializer.serialize_bytes(buf)
    }
}

impl<'de> de::Deserialize<'de> for Iovec {
    fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        Err(D::Error::custom("Cannot deserialize Element"))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn element_iovec() {
        let mut buf = [0x55; 1024];
        let iov = buf.as_mut_ptr() as *mut c_void;
        let len = buf.len();
        let e1 = Iovec::from((iov, len));
        let e2 = Iovec::from(buf.as_ref());
        assert_eq!(e1, e2);
    }

    #[test]
    fn element_debug() {
        let iov = 0x7000_0d48_aef0 as *mut c_void;
        let len = 512;
        let e = Iovec::from((iov, len));
        assert_eq!(
            format!("{:?}", e),
            "Element::Iovec { iov_base: 0x70000d48aef0, iov_len: 512 }"
        );
    }
}