1use crate::{ByteString, Bytes, storage::Storage};
2
3#[derive(Debug)]
8pub struct StorageVTable {
9 pub(crate) as_ptr: unsafe fn(*const u8, usize) -> *const u8,
10 pub(crate) len: unsafe fn(*const u8, usize) -> usize,
11 pub(crate) clone: unsafe fn(*const u8, usize) -> Option<(*const u8, usize)>,
12 pub(crate) drop: unsafe fn(*const u8, usize),
13}
14
15impl StorageVTable {
16 pub const fn new(
27 as_ptr: unsafe fn(*const u8, usize) -> *const u8,
28 len: unsafe fn(*const u8, usize) -> usize,
29 clone: unsafe fn(*const u8, usize) -> Option<(*const u8, usize)>,
30 drop: unsafe fn(*const u8, usize),
31 ) -> StorageVTable {
32 StorageVTable {
33 as_ptr,
34 len,
35 clone,
36 drop,
37 }
38 }
39}
40
41pub unsafe trait StorageExt: Send + Sync {
57 fn create(self) -> (*const u8, usize, &'static StorageVTable);
60}
61
62pub unsafe trait StorageExtStr: StorageExt + Sized {
68 fn create(self) -> (*const u8, usize, &'static StorageVTable) {
70 StorageExt::create(self)
71 }
72}
73
74impl Bytes {
75 pub fn from_ext<T: StorageExt>(val: T) -> Bytes {
79 let (addr, len, vtable) = val.create();
80
81 Bytes {
82 storage: Storage::from_stext(addr, len, vtable),
83 }
84 }
85}
86
87impl ByteString {
88 pub fn from_ext<T: StorageExtStr>(val: T) -> ByteString {
93 let (addr, len, vtable) = StorageExtStr::create(val);
94
95 unsafe {
96 ByteString::from_bytes_unchecked(Bytes {
97 storage: Storage::from_stext(addr, len, vtable),
98 })
99 }
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use crate::info::Kind;
107
108 fn as_ptr(addr: *const u8, _: usize) -> *const u8 {
109 addr
110 }
111
112 fn len(_: *const u8, len: usize) -> usize {
113 len
114 }
115
116 fn clone(_: *const u8, _: usize) -> Option<(*const u8, usize)> {
117 None
118 }
119
120 fn drop(addr: *const u8, len: usize) {
121 let ptr = std::ptr::slice_from_raw_parts_mut(addr.cast_mut(), len);
122 std::mem::drop(unsafe { Box::from_raw(ptr) });
123 }
124
125 struct Boxed(Box<[u8]>);
126
127 unsafe impl StorageExt for Boxed {
129 fn create(self) -> (*const u8, usize, &'static StorageVTable) {
130 static VTABLE: StorageVTable = StorageVTable::new(as_ptr, len, clone, drop);
131 let len = self.0.len();
132 (Box::into_raw(self.0).cast::<u8>(), len, &VTABLE)
133 }
134 }
135
136 #[test]
137 fn clone_copies_data() {
138 let data = vec![7u8; 100].into_boxed_slice();
139 let b = Bytes::from_ext(Boxed(data));
140 assert_eq!(b.info().kind, Kind::StExt);
141
142 let b2 = b.clone();
143 assert_eq!(b2.info().kind, Kind::Vec);
144 assert_eq!(b, b2);
145
146 let vtable = StorageVTable::new(as_ptr, len, clone, drop);
147 assert!(format!("{vtable:?}").contains("StorageVTable"));
148 }
149}