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}