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}