network-manager 0.11.0

Rust NetworkManager bindings
Documentation
use std::ops::Deref;
use std::mem;
use std::str;
use std::fmt;
use std::fmt::Write;
use std::ascii;

use errors::*;

#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Ssid {
    vec: Vec<u8>,
}

impl Ssid {
    pub fn new() -> Self {
        Ssid { vec: Vec::new() }
    }

    pub fn from_bytes<B>(bytes: B) -> Result<Self>
    where
        B: Into<Vec<u8>> + AsRef<[u8]>,
    {
        match bytes.as_ref().as_ssid_slice() {
            Ok(_) => Ok(unsafe { Ssid::from_bytes_unchecked(bytes) }),
            Err(e) => Err(e),
        }
    }

    unsafe fn from_bytes_unchecked<B>(bytes: B) -> Self
    where
        B: Into<Vec<u8>>,
    {
        Ssid { vec: bytes.into() }
    }
}

pub trait IntoSsid: Sized {
    fn into_ssid(self) -> Result<Ssid>;
}

impl Deref for Ssid {
    type Target = SsidSlice;

    #[inline]
    fn deref(&self) -> &SsidSlice {
        unsafe { mem::transmute(&self.vec[..]) }
    }
}

impl fmt::Debug for Ssid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self as &SsidSlice, f)
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SsidSlice {
    slice: [u8],
}

pub trait AsSsidSlice {
    fn as_ssid_slice(&self) -> Result<&SsidSlice>;
}

impl SsidSlice {
    pub fn as_str(&self) -> Result<&str> {
        Ok(str::from_utf8(&self.slice)?)
    }

    pub fn as_bytes(&self) -> &[u8] {
        unsafe { mem::transmute(&self.slice) }
    }
}

impl fmt::Debug for SsidSlice {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_char('"')?;
        for byte in self.as_bytes() {
            for c in ascii::escape_default(*byte) {
                f.write_char(c as char)?;
            }
        }
        f.write_char('"')
    }
}

impl AsSsidSlice for [u8] {
    fn as_ssid_slice(&self) -> Result<&SsidSlice> {
        if self.len() > 32 {
            bail!(ErrorKind::SSID(format!(
                "SSID length should not exceed 32: {} len",
                self.len()
            )))
        } else {
            Ok(unsafe { mem::transmute(self) })
        }
    }
}

impl AsSsidSlice for str {
    fn as_ssid_slice(&self) -> Result<&SsidSlice> {
        self.as_bytes().as_ssid_slice()
    }
}

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

    #[test]
    fn test_ssid_from_bytes_as_bytes() {
        let vec_u8 = vec![0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let ssid = Ssid::from_bytes(vec_u8.clone()).unwrap();
        let slice = &ssid as &SsidSlice;
        let as_bytes = slice.as_bytes();
        assert_eq!(vec_u8, as_bytes);
    }

    #[test]
    fn test_ssid_from_bytes_as_str() {
        let vec_u8 = vec![0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let ssid = Ssid::from_bytes(vec_u8.clone()).unwrap();
        let slice = &ssid as &SsidSlice;
        let as_str = slice.as_str().unwrap();
        assert_eq!(vec_u8, as_str.as_bytes());
    }

    #[test]
    fn test_ssid_from_bytes_eq() {
        let from_string = Ssid::from_bytes("hello".to_string()).unwrap();
        let vec_u8 = vec![0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let from_vec_u8 = Ssid::from_bytes(vec_u8).unwrap();
        assert_eq!(from_string, from_vec_u8);
    }

    #[test]
    fn test_as_ssid_slice() {
        let slice_from_str = "hello".as_ssid_slice().unwrap();
        let ssid_u8 = [0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let slice_from_u8 = (&ssid_u8 as &[u8]).as_ssid_slice().unwrap();
        assert_eq!(slice_from_str, slice_from_u8);
    }

    #[test]
    fn test_ssid_debug() {
        let ssid = Ssid::from_bytes(b"hello\0\x7F".to_vec()).unwrap();
        let debug = format!("{:?}", ssid);
        assert_eq!(debug, "\"hello\\x00\\x7f\"");
    }

    #[test]
    fn test_ssid_slice_debug() {
        let ssid = Ssid::from_bytes(b"hello\0\x7F".to_vec()).unwrap();
        let slice = &ssid as &SsidSlice;
        let debug = format!("{:?}", slice);
        assert_eq!(debug, "\"hello\\x00\\x7f\"");
    }
}