rumtk-core 0.17.0

Core library for providing general functionality to support the other RUMTK crates. See rumtk-hl7-v2 crate as example
Documentation
/*
 *     rumtk attempts to implement HL7 and medical protocols for interoperability in medicine.
 *     This toolkit aims to be reliable, simple, performant, and standards compliant.
 *     Copyright (C) 2026  Luis M. Santos, M.D. <lsantos@medicalmasses.com>
 *     Copyright (C) 2026  MedicalMasses L.L.C. <contact@medicalmasses.com>
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
use crate::base::{RUMResult, RUMVec};
use crate::buffers::buffer_to_str;
use crate::mem::{as_slice_mut, copy_from_slice, AsPtr, AsSlice, SizedType};
use rumtk_arena::dune::Dune;
use rumtk_arena::rumtk_dune_new;
use std::cmp::PartialEq;
use std::mem;
use std::ops::DerefMut;
use std::ops::{Deref, RangeTo, RangeToInclusive};
use std::ops::{Index, Range, RangeFull};
use std::sync::LazyLock;

#[derive(Default, Debug, Clone)]
enum RUMBufferDataPtr {
    StaticBuffer(&'static [u8]),
    String(String),
    Vec(RUMVec<u8>),
    Arena(Dune),
    #[default]
    None
}

impl PartialEq for RUMBufferDataPtr {
    fn eq(&self, other: &Self) -> bool {
        mem::discriminant(self) == mem::discriminant(other)
    }
}

pub type RUMBufferInner = RUMBufferDataPtr;

const EMPTY_BUFFER_DATA: [u8;0] = [0;0];
static EMPTY_RUMBUFFER: LazyLock<RUMBuffer> = LazyLock::new(|| RUMBuffer::new());

///
/// The [RUMBuffer] type is meant to be a very lightweight owned buffer pointer. The impetus for building
/// this type is that benchmarking showed a potential vector getting allocated by the **bytes** crate.
/// I was using the bytes crate before because it is a very solid crate. However, the vector allocations worried me.
/// It was likely part of that crates interior mutability strategy with vtables but it was one of a few
/// areas consuming a lot of time and most importantly consuming kernel time by invoking malloc.
///
/// ## Example
/// ### Creation
/// ```
/// use rumtk_core::buffers::*;
///
/// let buffer = RUMBuffer::from("Hello World!");
/// let expected = b"Hello World!";
///
/// assert_eq!(&buffer[..], expected, "Could not create RUMBuffer!");
/// ```
///
/// ### Split Buffer
/// ```
/// use rumtk_core::buffers::*;
///
/// let mut buffer = RUMBuffer::from("Hello World!");
/// let section = buffer.split_to(5);
/// let expected = b"Hello";
///
/// assert_eq!(&section[..], expected, "Could not create RUMBuffer!");
/// ```
///
#[derive(Debug)]
pub struct RUMBuffer {
    data: RUMBufferInner,
    ptr: *const u8,
    size: usize,
}

impl RUMBuffer {
    #[inline]
    pub const fn new() -> Self {
        let data_length = 0;
        let ptr = EMPTY_BUFFER_DATA.as_ptr();
        Self {
            data: RUMBufferDataPtr::None,
            ptr,
            size: data_length,
        }
    }

    #[inline]
    pub fn from_slice(data: &[u8]) -> Self {
        if data.is_empty() {
            return Self::new();
        }

        let data_length = data.len();
        let mut mem = rumtk_dune_new!(data_length);
        let mut ptr = mem.allocate_raw(data_length).unwrap();
        let dst = as_slice_mut(ptr, data_length);
        copy_from_slice(&data[..], dst);
        Self {
            data: RUMBufferDataPtr::Arena(mem),
            ptr,
            size: data_length,
        }
    }

    #[inline]
    pub fn from_vec(mut data: Vec<u8>) -> Self {
        let mut ptr = data.as_mut_ptr();
        let size = data.len();
        Self {
            data: RUMBufferDataPtr::Vec(data),
            ptr,
            size,
        }
    }

    #[inline]
    pub fn from_string(mut data: String) -> Self {
        let mut ptr = data.as_mut_ptr();
        let size = data.len();
        Self {
            data: RUMBufferDataPtr::String(data),
            ptr,
            size,
        }
    }

    #[inline]
    pub fn from_static(mut data: &'static [u8]) -> Self {
        let mut ptr = data.as_mut_ptr();
        let size = data.len();
        Self {
            data: RUMBufferDataPtr::StaticBuffer(data),
            ptr,
            size,
        }
    }

    #[inline]
    pub fn split_to(&mut self, offset: usize) -> Self {
        debug_assert!(offset <= self.size, "offset too large");
        let copy = Self {
            data: RUMBufferDataPtr::None,
            ptr: self.ptr,
            size: offset,
        };
        self.ptr = unsafe { self.ptr.add(offset) };
        self.size -= offset;
        copy
    }

    #[inline]
    pub fn freeze(&self) -> Self {
        Self {
            data: RUMBufferDataPtr::None,
            ptr: self.ptr,
            size: self.size,
        }
    }

    #[inline]
    pub fn to_vec(&self) -> RUMVec<u8> {
        self.as_slice().to_vec()
    }

    #[inline]
    pub fn as_str(&self) -> RUMResult<&str> {
        buffer_to_str(self)
    }

    #[inline]
    pub fn truncate(&mut self, len: usize) {
        self.size = len;
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.size == 0
    }

    #[inline]
    pub fn is_buffer(&self) -> bool {
        !self.is_view()
    }

    #[inline]
    pub fn is_view(&self) -> bool {
        self.data == RUMBufferDataPtr::None
    }
}

impl Iterator for RUMBuffer {
    type Item = u8;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.size == 0 { return None };

        let v = self[0];
        self.ptr = unsafe { self.ptr.add(1) };
        Some(v)
    }
}

impl SizedType for RUMBuffer {
    fn size(&self) -> usize {
        self.size
    }
}

impl AsPtr for RUMBuffer {
    #[inline(always)]
    fn as_ptr(&self) -> *const u8 {
        self.ptr
    }
    #[inline(always)]
    fn as_mut_ptr(&mut self) -> *mut u8 {
        self.ptr as *mut u8
    }
}

impl AsSlice for RUMBuffer {  }

impl AsRef<[u8]> for RUMBuffer {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self.as_slice()
    }
}

impl Deref for RUMBuffer {
    type Target = [u8];
    #[inline]
    fn deref(&self) -> &Self::Target {
        self.as_slice()
    }
}

impl DerefMut for RUMBuffer {
    #[inline]
    fn deref_mut(&mut self) -> &mut [u8] {
        self.as_slice_mut()
    }
}

impl PartialEq for RUMBuffer {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl Default for RUMBuffer {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl Clone for RUMBuffer {
    #[inline]
    fn clone(&self) -> Self {
        self.freeze()
    }
}

/*
impl Drop for RUMBuffer {
    fn drop(&mut self) {
        match self.data.clone() {
            Some(mem) => {
                drop(mem)
            },
            None => {}
        }
    }
}
*/
unsafe impl Send for RUMBuffer {}
unsafe impl Sync for RUMBuffer {}

///////////////////// Indexing ////////////////////////////////////

impl Index<usize> for RUMBuffer {
    type Output = u8;
    #[inline]
    fn index(&self, i: usize) -> &Self::Output {
        &self.as_slice()[i]
    }
}

impl Index<Range<usize>> for RUMBuffer {
    type Output = [u8];
    #[inline]
    fn index(&self, i: Range<usize>) -> &Self::Output {
        &self.as_slice()[i.start..i.end]
    }
}

impl Index<RangeTo<usize>> for RUMBuffer {
    type Output = [u8];
    #[inline]
    fn index(&self, i: RangeTo<usize>) -> &Self::Output {
        &self.as_slice()[..i.end]
    }
}

impl Index<RangeToInclusive<usize>> for RUMBuffer {
    type Output = [u8];
    #[inline]
    fn index(&self, i: RangeToInclusive<usize>) -> &Self::Output {
        &self.as_slice()[..=i.end]
    }
}

impl Index<RangeFull> for RUMBuffer {
    type Output = [u8];
    #[inline]
    fn index(&self, i: RangeFull) -> &Self::Output {
        self.as_slice()
    }
}

/////////////////////// Conversions ////////////////////////////////
impl From<String> for RUMBuffer {
    #[inline]
    fn from(data: String) -> Self {
        Self::from_string(data)
    }
}
impl From<Vec<u8>> for RUMBuffer {
    #[inline]
    fn from(data: Vec<u8>) -> Self {
        Self::from_vec(data)
    }
}

impl From<&RUMVec<u8>> for RUMBuffer {
    #[inline]
    fn from(data: &RUMVec<u8>) -> Self {
        Self::from_slice(data.as_slice())
    }
}

impl From<&[u8]> for RUMBuffer {
    #[inline]
    fn from(data: &[u8]) -> Self {
        Self::from_slice(data)
    }
}

impl<const N: usize> From<&[u8; N]> for RUMBuffer {
    #[inline]
    fn from(data: &[u8; N]) -> Self {
        Self::from(data.as_slice())
    }
}

impl From<&str> for RUMBuffer {
    #[inline]
    fn from(data: &str) -> Self {
        Self::from(data.as_bytes())
    }
}