diff options
Diffstat (limited to 'serde_v8/magic/v8slice.rs')
-rw-r--r-- | serde_v8/magic/v8slice.rs | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/serde_v8/magic/v8slice.rs b/serde_v8/magic/v8slice.rs index 6950e29d9..452c857a3 100644 --- a/serde_v8/magic/v8slice.rs +++ b/serde_v8/magic/v8slice.rs @@ -3,7 +3,9 @@ use std::ops::Deref; use std::ops::DerefMut; use std::ops::Range; +use std::rc::Rc; +use super::rawbytes; use super::transl8::FromV8; /// A V8Slice encapsulates a slice that's been borrowed from a JavaScript @@ -117,3 +119,52 @@ impl AsMut<[u8]> for V8Slice { self.as_slice_mut() } } + +// Implement V8Slice -> bytes::Bytes +impl V8Slice { + fn rc_into_byte_parts(self: Rc<Self>) -> (*const u8, usize, *mut V8Slice) { + let (ptr, len) = { + let slice = self.as_ref(); + (slice.as_ptr(), slice.len()) + }; + let rc_raw = Rc::into_raw(self); + let data = rc_raw as *mut V8Slice; + (ptr, len, data) + } +} + +impl From<V8Slice> for bytes::Bytes { + fn from(v8slice: V8Slice) -> Self { + let (ptr, len, data) = Rc::new(v8slice).rc_into_byte_parts(); + rawbytes::RawBytes::new_raw(ptr, len, data.cast(), &V8SLICE_VTABLE) + } +} + +// NOTE: in the limit we could avoid extra-indirection and use the C++ shared_ptr +// but we can't store both the underlying data ptr & ctrl ptr ... so instead we +// use a shared rust ptr (Rc/Arc) that itself controls the C++ shared_ptr +const V8SLICE_VTABLE: rawbytes::Vtable = rawbytes::Vtable { + clone: v8slice_clone, + drop: v8slice_drop, +}; + +unsafe fn v8slice_clone( + data: &rawbytes::AtomicPtr<()>, + ptr: *const u8, + len: usize, +) -> bytes::Bytes { + let rc = Rc::from_raw(*data as *const V8Slice); + let (_, _, data) = rc.clone().rc_into_byte_parts(); + std::mem::forget(rc); + // NOTE: `bytes::Bytes` does bounds checking so we trust its ptr, len inputs + // and must use them to allow cloning Bytes it has sliced + rawbytes::RawBytes::new_raw(ptr, len, data.cast(), &V8SLICE_VTABLE) +} + +unsafe fn v8slice_drop( + data: &mut rawbytes::AtomicPtr<()>, + _: *const u8, + _: usize, +) { + drop(Rc::from_raw(*data as *const V8Slice)) +} |