praborrow_logistics/
lib.rs

1//! Zero-copy buffer abstraction for raw byte streams.
2//!
3//! Provides `RawResource` for managing raw byte buffers without allocation overhead.
4//! Uses `ManuallyDrop` to take ownership of data while exposing raw pointers.
5//!
6//! # Safety
7//!
8//! This module uses unsafe code to manage memory manually. The `RawResource` struct
9//! takes ownership of a `Vec<u8>` via `ManuallyDrop`, preventing automatic deallocation.
10//! The `Drop` implementation properly reconstructs the `Vec` to ensure memory is freed.
11//!
12//! Caller is responsible for ensuring the buffer outlives all references to it.
13
14#![no_std]
15
16extern crate alloc;
17
18use alloc::vec::Vec;
19use bytes::Bytes;
20
21/// Error returned by logistics operations.
22#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
23pub enum LogisticsError {
24    /// Attempted to refine an empty buffer.
25    #[error("Cannot refine empty data: buffer must contain at least one byte")]
26    EmptyBuffer,
27}
28
29/// A zero-copy buffer resource representing "Hilirisasi Data" (Downstreaming Data).
30///
31/// This struct wraps `bytes::Bytes` to provide efficient, reference-counted
32/// access to contiguous memory without unnecessary copying.
33#[doc(alias = "PinnedBuffer")]
34#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct RawResource {
36    inner: Bytes,
37}
38
39// Bytes is Send + Sync
40unsafe impl Send for RawResource {}
41unsafe impl Sync for RawResource {}
42
43impl RawResource {
44    /// HILIRISASI DATA: Refines raw data into a downstreamable resource.
45    ///
46    /// Consumes a `Vec<u8>` into a `Bytes` object (zero-copy if possible).
47    ///
48    /// # Errors
49    ///
50    /// Returns an error if the input data is empty.
51    pub fn refine(data: Vec<u8>) -> Result<Self, LogisticsError> {
52        if data.is_empty() {
53            return Err(LogisticsError::EmptyBuffer);
54        }
55
56        Ok(Self {
57            inner: Bytes::from(data),
58        })
59    }
60
61    /// Returns the raw pointer to the resource data.
62    #[inline]
63    pub fn as_ptr(&self) -> *const u8 {
64        self.inner.as_ptr()
65    }
66
67    /// Returns the length of the resource data in bytes.
68    #[inline]
69    pub fn len(&self) -> usize {
70        self.inner.len()
71    }
72
73    /// Returns `true` if the resource has zero length.
74    #[inline]
75    pub fn is_empty(&self) -> bool {
76        self.inner.is_empty()
77    }
78
79    /// Returns a byte slice of the resource.
80    ///
81    /// # Safety
82    ///
83    /// This method is safe. The `unsafe` keyword is kept for backward compatibility
84    /// but the implementation delegates to safe `Bytes::as_ref()`.
85    ///
86    /// # Safe Usage
87    /// The returned slice is tied to the lifetime of `self`.
88    pub unsafe fn as_slice(&self) -> &[u8] {
89        &self.inner
90    }
91
92    /// Returns a safe slice.
93    pub fn as_bytes(&self) -> &[u8] {
94        &self.inner
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[test]
103    fn test_refine_success() {
104        let data = alloc::vec![1, 2, 3, 4, 5];
105        let resource = RawResource::refine(data).expect("should succeed");
106        assert_eq!(resource.len(), 5);
107        assert!(!resource.is_empty());
108    }
109
110    #[test]
111    fn test_refine_empty_fails() {
112        let data: Vec<u8> = alloc::vec![];
113        let result = RawResource::refine(data);
114        assert!(result.is_err());
115    }
116
117    #[test]
118    fn test_as_slice() {
119        let data = alloc::vec![10, 20, 30];
120        let resource = RawResource::refine(data).expect("should succeed");
121        let slice = unsafe { resource.as_slice() };
122        assert_eq!(slice, &[10, 20, 30]);
123    }
124
125    #[test]
126    fn test_drop_is_called() {
127        // This test verifies Drop doesn't panic. In a real scenario,
128        // you'd use a custom allocator to verify deallocation.
129        let data = alloc::vec![1, 2, 3, 4, 5];
130        let resource = RawResource::refine(data).expect("should succeed");
131        drop(resource);
132        // If we get here without panic/leak detector complaints, Drop works
133    }
134}