flat_message 0.2.1

Zero-copy, schema-less serialization and deserialization fast library for Rust.
Documentation
use std::mem;

use super::SerDeVec;
use super::SerDeVecType;
use crate::size;
use crate::common::data_format::DataFormat;

const SIZE_FORMAT: size::Format = size::Format::U8withExtension;

/// Implementation for &str
unsafe impl<'a, TVecType: SerDeVecType<&'a str>> SerDeVec<'a, TVecType> for &'a str {
    const DATA_FORMAT: DataFormat = DataFormat::String;
    #[inline(always)]
    unsafe fn from_buffer_unchecked(buf: &'a [u8], pos: usize) -> TVecType {
        let p = buf.as_ptr();
        let (count, slen) = size::read_unchecked(p, pos, SIZE_FORMAT);
        if count == 0 {
            TVecType::new()
        } else {
            let mut result = TVecType::with_capacity(count);
            let mut pos = pos + slen;
            for _ in 0..count {
                let (len, slen) = size::read_unchecked(p, pos, SIZE_FORMAT);
                let s = std::slice::from_raw_parts(p.add(pos + slen), len);
                result.push(std::str::from_utf8_unchecked(s));
                pos += slen + len;
            }
            result
        }
    }
    #[inline(always)]
    fn from_buffer(buf: &'a [u8], pos: usize) -> Option<TVecType> {
        let (count, slen) = unsafe { size::read(buf.as_ptr(), pos, buf.len(), SIZE_FORMAT)? };
        if count == 0 {
            Some(TVecType::new())
        } else {
            let p = buf.as_ptr();
            // assume -> minim one byte per string (with value 0 for pottential mpty strings)
            // minimal size should be count * 1+sled for all strings
            let min_size = pos + slen + count;
            if min_size > buf.len() {
                return None;
            }
            let mut result = TVecType::with_capacity(count.min(1024));
            let mut pos = pos + slen;
            for _ in 0..count {
                let (len, size_len) = unsafe { size::read(p, pos, buf.len(), SIZE_FORMAT)? };
                let end = pos + size_len + len;
                if end > buf.len() {
                    return None;
                }
                let s = &buf[pos + size_len..end];
                if let Ok(new_string_slice) = std::str::from_utf8(s) {
                    result.push(new_string_slice);
                } else {
                    return None;
                }
                pos = end;
            }
            Some(result)
        }
    }
    #[inline(always)]
    unsafe fn write(obj: &TVecType, p: *mut u8, pos: usize) -> usize {
        let count = obj.len() as u32;
        unsafe {
            let count_len = size::write(p, pos, count, SIZE_FORMAT);
            let mut offset = pos + count_len;
            for s in obj.iter() {
                let string_len = s.len() as u32;
                let string_len_size = size::write(p, offset, string_len, SIZE_FORMAT);
                offset += string_len_size;
                std::ptr::copy_nonoverlapping(s.as_ptr(), p.add(offset), s.len());
                offset += string_len as usize;
            }
            offset
        }
    }
    #[inline(always)]
    fn size(obj: &TVecType) -> usize {
        let mut total_size = size::len(obj.len() as u32, SIZE_FORMAT);
        for s in obj.iter() {
            total_size += size::len(s.len() as u32, SIZE_FORMAT) + s.len();
        }
        total_size
    }
}

/// Implementation for String
unsafe impl<'a, TVecType: SerDeVecType<String>> SerDeVec<'a, TVecType> for String {
    const DATA_FORMAT: DataFormat = DataFormat::String;
    #[inline(always)]
    unsafe fn from_buffer_unchecked(buf: &'a [u8], pos: usize) -> TVecType {
        let p = buf.as_ptr();
        let (count, slen) = size::read_unchecked(p, pos, SIZE_FORMAT);
        if count == 0 {
            TVecType::new()
        } else {
            let mut result: TVecType = TVecType::with_capacity(count);
            let mut pos = pos + slen;
            let mut result_inner_data_ptr = result.as_mut_ptr();
            for _ in 0..count {
                let (len, slen) = size::read_unchecked(p, pos, SIZE_FORMAT);
                let s = std::slice::from_raw_parts(p.add(pos + slen), len);
                let actual_string = std::str::from_utf8_unchecked(s).to_string();
                std::ptr::copy_nonoverlapping(&actual_string, result_inner_data_ptr, 1);
                result_inner_data_ptr = result_inner_data_ptr.add(1);
                pos += slen + len;
                mem::forget(actual_string);
            }
            result.set_len(count);
            result
        }
    }
    #[inline(always)]
    fn from_buffer(buf: &'a [u8], pos: usize) -> Option<TVecType> {
        let (count, slen) = unsafe { size::read(buf.as_ptr(), pos, buf.len(), SIZE_FORMAT)? };
        if count == 0 {
            Some(TVecType::new())
        } else {
            let p = buf.as_ptr();
            // assume -> minim one byte per string (with value 0 for pottential mpty strings)
            // minimal size should be count * 1+sled for all strings
            let min_size = pos + slen + count;
            if min_size > buf.len() {
                return None;
            }
            let mut result = TVecType::with_capacity(count.min(1024));
            let mut pos = pos + slen;
            for _ in 0..count {
                let (len, size_len) = unsafe { size::read(p, pos, buf.len(), SIZE_FORMAT)? };
                let end = pos + size_len + len;
                if end > buf.len() {
                    return None;
                }
                let s = &buf[pos + size_len..end];
                if let Ok(new_string_slice) = std::str::from_utf8(s) {
                    result.push(new_string_slice.to_string());
                } else {
                    return None;
                }
                pos = end;
            }
            Some(result)
        }
    }
    #[inline(always)]
    unsafe fn write(obj: &TVecType, p: *mut u8, pos: usize) -> usize {
        let count = obj.len() as u32;
        unsafe {
            let count_len = size::write(p, pos, count, SIZE_FORMAT);
            let mut offset = pos + count_len;
            for s in obj.iter() {
                let string_len = s.len() as u32;
                let string_len_size = size::write(p, offset, string_len, SIZE_FORMAT);
                offset += string_len_size;
                std::ptr::copy_nonoverlapping(s.as_ptr(), p.add(offset), s.len());
                offset += string_len as usize;
            }
            offset
        }
    }
    #[inline(always)]
    fn size(obj: &TVecType) -> usize {
        let mut total_size = size::len(obj.len() as u32, SIZE_FORMAT);
        for s in obj.iter() {
            total_size += size::len(s.len() as u32, SIZE_FORMAT) + s.len();
        }
        total_size
    }
}