diameter 0.7.1

Rust Implementation of the Diameter Protocol.
Documentation
use crate::error::{Error, Result};
use std::fmt;
use std::io::Read;
use std::io::Write;

#[derive(Debug, Clone)]
pub struct UTF8String(String);

impl UTF8String {
    pub fn new(value: &str) -> UTF8String {
        UTF8String(value.to_string())
    }

    pub fn value(&self) -> &str {
        &self.0
    }

    pub fn decode_from<R: Read>(reader: &mut R, len: usize) -> Result<UTF8String> {
        let mut b = vec![0u8; len];
        reader.read_exact(&mut b)?;

        let s = String::from_utf8(b.to_vec())
            .map_err(|e| Error::DecodeError(format!("invalid UTF8String: {}", e)))?;
        Ok(UTF8String(s))
    }

    pub fn encode_to<W: Write>(&self, writer: &mut W) -> Result<()> {
        writer.write_all(self.0.as_bytes())?;
        Ok(())
    }

    pub fn length(&self) -> u32 {
        self.0.len() as u32
    }
}

impl fmt::Display for UTF8String {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use super::*;

    #[test]
    fn test_encode_decode_ascii() {
        let str = "Hello World";
        let avp = UTF8String::new(str);
        let mut encoded = Vec::new();
        avp.encode_to(&mut encoded).unwrap();
        let mut cursor = Cursor::new(&encoded);
        let avp = UTF8String::decode_from(&mut cursor, str.len()).unwrap();
        assert_eq!(avp.value(), str);
    }

    #[test]
    fn test_encode_decode_utf8() {
        let str = "世界,你好";
        let avp = UTF8String::new(str);
        let mut encoded = Vec::new();
        avp.encode_to(&mut encoded).unwrap();
        let mut cursor = Cursor::new(&encoded);
        let avp = UTF8String::decode_from(&mut cursor, str.len()).unwrap();
        assert_eq!(avp.value(), str);
    }

    #[test]
    fn test_decode_invalid_utf8() {
        let bytes = vec![0x61, 0x62, 0x63, 0x64, 0x80];
        let mut cursor = Cursor::new(&bytes);
        match UTF8String::decode_from(&mut cursor, 5) {
            Err(Error::DecodeError(msg)) => {
                assert_eq!(
                    msg,
                    "invalid UTF8String: invalid utf-8 sequence of 1 bytes from index 4"
                );
            }
            Err(_) => panic!("Expected a DecodeError, but got a different error"),
            Ok(_) => panic!("Expected an error, but got Ok"),
        }
    }
}