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    // EmptyBuffer removed as empty buffers are now allowed
25}
26
27/// A zero-copy buffer resource representing "Hilirisasi Data" (Downstreaming Data).
28///
29/// This struct wraps `bytes::Bytes` to provide efficient, reference-counted
30/// access to contiguous memory without unnecessary copying.
31#[doc(alias = "PinnedBuffer")]
32#[derive(Clone, Debug, PartialEq, Eq)]
33pub struct RawResource {
34    inner: Bytes,
35}
36
37// Bytes is Send + Sync
38unsafe impl Send for RawResource {}
39unsafe impl Sync for RawResource {}
40
41impl RawResource {
42    /// HILIRISASI DATA: Refines raw data into a downstreamable resource.
43    ///
44    /// Consumes a `Vec<u8>` into a `Bytes` object (zero-copy if possible).
45    ///
46    /// # Errors
47    ///
48    /// Returns an error if the input data is empty.
49    pub fn refine(data: Vec<u8>) -> Result<Self, LogisticsError> {
50        // Empty buffers are now valid "zero-byte resources"
51        Ok(Self {
52            inner: Bytes::from(data),
53        })
54    }
55
56    /// Returns the raw pointer to the resource data.
57    #[inline]
58    pub fn as_ptr(&self) -> *const u8 {
59        self.inner.as_ptr()
60    }
61
62    /// Returns the length of the resource data in bytes.
63    #[inline]
64    pub fn len(&self) -> usize {
65        self.inner.len()
66    }
67
68    /// Returns `true` if the resource has zero length.
69    #[inline]
70    pub fn is_empty(&self) -> bool {
71        self.inner.is_empty()
72    }
73
74    /// Returns a byte slice of the resource.
75    ///
76    /// # Safety
77    ///
78    /// This method is safe. The `unsafe` keyword is kept for backward compatibility
79    /// but the implementation delegates to safe `Bytes::as_ref()`.
80    ///
81    /// # Safe Usage
82    /// The returned slice is tied to the lifetime of `self`.
83    #[deprecated(note = "Use as_bytes() instead")]
84    pub unsafe fn as_slice(&self) -> &[u8] {
85        &self.inner
86    }
87
88    /// Returns a safe slice.
89    pub fn as_bytes(&self) -> &[u8] {
90        &self.inner
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97
98    #[test]
99    fn test_refine_success() {
100        let data = alloc::vec![1, 2, 3, 4, 5];
101        let resource = RawResource::refine(data).expect("should succeed");
102        assert_eq!(resource.len(), 5);
103        assert!(!resource.is_empty());
104    }
105
106    #[test]
107    fn test_refine_empty_success() {
108        let data: Vec<u8> = alloc::vec![];
109        let resource = RawResource::refine(data).expect("should succeed now");
110        assert!(resource.is_empty());
111        assert_eq!(resource.len(), 0);
112    }
113
114    #[test]
115    #[allow(deprecated)]
116    fn test_as_slice() {
117        let data = alloc::vec![10, 20, 30];
118        let resource = RawResource::refine(data).expect("should succeed");
119        let slice = unsafe { resource.as_slice() };
120        assert_eq!(slice, &[10, 20, 30]);
121    }
122
123    #[test]
124    fn test_drop_is_called() {
125        // This test verifies Drop doesn't panic. In a real scenario,
126        // you'd use a custom allocator to verify deallocation.
127        let data = alloc::vec![1, 2, 3, 4, 5];
128        let resource = RawResource::refine(data).expect("should succeed");
129        drop(resource);
130        // If we get here without panic/leak detector complaints, Drop works
131    }
132}