Skip to content

Commit 169cd44

Browse files
committed
add Bytes::downcast_impl to extract underlying implementation
1 parent 4231f69 commit 169cd44

File tree

2 files changed

+83
-2
lines changed

2 files changed

+83
-2
lines changed

src/bytes.rs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use core::any::TypeId;
12
use core::iter::FromIterator;
23
use core::ops::{Deref, RangeBounds};
34
use core::{cmp, fmt, hash, mem, ptr, slice, usize};
@@ -114,6 +115,9 @@ pub unsafe trait BytesImpl: 'static {
114115
/// Decompose `Self` into parts used by `Bytes`.
115116
fn into_bytes_parts(this: Self) -> (AtomicPtr<()>, *const u8, usize);
116117

118+
/// Creates itself directly from the raw bytes parts decomposed with `into_bytes_parts`.
119+
unsafe fn from_bytes_parts(data: &mut AtomicPtr<()>, ptr: *const u8, len: usize) -> Self;
120+
117121
/// Returns new `Bytes` based on the current parts.
118122
unsafe fn clone(data: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes;
119123

@@ -132,6 +136,7 @@ pub unsafe trait BytesImpl: 'static {
132136
}
133137

134138
struct Vtable {
139+
type_id: fn() -> TypeId,
135140
/// fn(data, ptr, len)
136141
clone: unsafe fn(&AtomicPtr<()>, *const u8, usize) -> Bytes,
137142
/// fn(data, ptr, len)
@@ -192,6 +197,7 @@ impl Bytes {
192197
#[cfg(not(all(loom, test)))]
193198
pub const fn from_static(bytes: &'static [u8]) -> Bytes {
194199
const STATIC_VTABLE: Vtable = Vtable {
200+
type_id: TypeId::of::<StaticImpl>,
195201
clone: <StaticImpl as BytesImpl>::clone,
196202
will_truncate: <StaticImpl as BytesImpl>::will_truncate,
197203
into_vec: <StaticImpl as BytesImpl>::into_vec,
@@ -209,6 +215,7 @@ impl Bytes {
209215
#[cfg(all(loom, test))]
210216
pub fn from_static(bytes: &'static [u8]) -> Bytes {
211217
const STATIC_VTABLE: Vtable = Vtable {
218+
type_id: TypeId::of::<StaticImpl>,
212219
clone: <StaticImpl as BytesImpl>::clone,
213220
will_truncate: <StaticImpl as BytesImpl>::will_truncate,
214221
into_vec: <StaticImpl as BytesImpl>::into_vec,
@@ -235,6 +242,7 @@ impl Bytes {
235242
len,
236243
data,
237244
vtable: &Vtable {
245+
type_id: TypeId::of::<T>,
238246
clone: T::clone,
239247
will_truncate: T::will_truncate,
240248
into_vec: T::into_vec,
@@ -543,6 +551,19 @@ impl Bytes {
543551
self.truncate(0);
544552
}
545553

554+
/// Downcast this `Bytes` into its underlying implementation.
555+
#[inline]
556+
pub fn downcast_impl<T: BytesImpl>(self) -> Result<T, Bytes> {
557+
if TypeId::of::<T>() == (self.vtable.type_id)() {
558+
Ok(unsafe {
559+
let this = &mut *mem::ManuallyDrop::new(self);
560+
T::from_bytes_parts(&mut this.data, this.ptr, this.len)
561+
})
562+
} else {
563+
Err(self)
564+
}
565+
}
566+
546567
// private
547568

548569
#[inline]
@@ -891,6 +912,7 @@ impl From<Bytes> for Vec<u8> {
891912
impl fmt::Debug for Vtable {
892913
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
893914
f.debug_struct("Vtable")
915+
.field("type_id", &self.type_id)
894916
.field("clone", &(self.clone as *const ()))
895917
.field("will_truncate", &(self.will_truncate as *const ()))
896918
.field("into_vec", &(self.into_vec as *const ()))
@@ -906,7 +928,15 @@ struct StaticImpl(&'static [u8]);
906928
unsafe impl BytesImpl for StaticImpl {
907929
fn into_bytes_parts(this: Self) -> (AtomicPtr<()>, *const u8, usize) {
908930
let mut bytes = mem::ManuallyDrop::new(Bytes::from_static(this.0));
909-
(mem::take(&mut bytes.data), bytes.ptr, bytes.len)
931+
(
932+
mem::replace(&mut bytes.data, AtomicPtr::default()),
933+
bytes.ptr,
934+
bytes.len,
935+
)
936+
}
937+
938+
unsafe fn from_bytes_parts(_data: &mut AtomicPtr<()>, ptr: *const u8, len: usize) -> Self {
939+
StaticImpl(slice::from_raw_parts(ptr, len))
910940
}
911941

912942
unsafe fn clone(_: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes {
@@ -932,7 +962,6 @@ struct PromotableOddImpl(Promotable);
932962

933963
enum Promotable {
934964
Owned(Box<[u8]>),
935-
#[allow(dead_code)]
936965
Shared(SharedImpl),
937966
}
938967

@@ -952,6 +981,12 @@ unsafe impl BytesImpl for PromotableEvenImpl {
952981
(AtomicPtr::new(data.cast()), ptr, len)
953982
}
954983

984+
unsafe fn from_bytes_parts(data: &mut AtomicPtr<()>, ptr: *const u8, len: usize) -> Self {
985+
PromotableEvenImpl(promotable_from_bytes_parts(data, ptr, len, |shared| {
986+
ptr_map(shared.cast(), |addr| addr & !KIND_MASK)
987+
}))
988+
}
989+
955990
unsafe fn clone(data: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes {
956991
let shared = data.load(Ordering::Acquire);
957992
let kind = shared as usize & KIND_MASK;
@@ -994,6 +1029,30 @@ unsafe impl BytesImpl for PromotableEvenImpl {
9941029
}
9951030
}
9961031

1032+
unsafe fn promotable_from_bytes_parts(
1033+
data: &mut AtomicPtr<()>,
1034+
ptr: *const u8,
1035+
len: usize,
1036+
f: fn(*mut ()) -> *mut u8,
1037+
) -> Promotable {
1038+
let shared = data.with_mut(|p| *p);
1039+
let kind = shared as usize & KIND_MASK;
1040+
1041+
if kind == KIND_ARC {
1042+
Promotable::Shared(SharedImpl::from_bytes_parts(data, ptr, len))
1043+
} else {
1044+
debug_assert_eq!(kind, KIND_VEC);
1045+
1046+
let buf = f(shared);
1047+
1048+
let cap = (ptr as usize - buf as usize) + len;
1049+
1050+
let vec = Vec::from_raw_parts(buf, cap, cap);
1051+
1052+
Promotable::Owned(vec.into_boxed_slice())
1053+
}
1054+
}
1055+
9971056
unsafe fn promotable_into_vec(
9981057
data: &mut AtomicPtr<()>,
9991058
ptr: *const u8,
@@ -1034,6 +1093,12 @@ unsafe impl BytesImpl for PromotableOddImpl {
10341093
(AtomicPtr::new(ptr.cast()), ptr, len)
10351094
}
10361095

1096+
unsafe fn from_bytes_parts(data: &mut AtomicPtr<()>, ptr: *const u8, len: usize) -> Self {
1097+
PromotableOddImpl(promotable_from_bytes_parts(data, ptr, len, |shared| {
1098+
shared.cast()
1099+
}))
1100+
}
1101+
10371102
unsafe fn clone(data: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes {
10381103
let shared = data.load(Ordering::Acquire);
10391104
let kind = shared as usize & KIND_MASK;
@@ -1114,6 +1179,14 @@ unsafe impl BytesImpl for SharedImpl {
11141179
(AtomicPtr::new(this.shared.cast()), this.offset, this.len)
11151180
}
11161181

1182+
unsafe fn from_bytes_parts(data: &mut AtomicPtr<()>, ptr: *const u8, len: usize) -> Self {
1183+
SharedImpl {
1184+
shared: (data.with_mut(|p| *p)).cast(),
1185+
offset: ptr,
1186+
len,
1187+
}
1188+
}
1189+
11171190
unsafe fn clone(data: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes {
11181191
let shared = data.load(Ordering::Relaxed);
11191192
shallow_clone_arc(shared as _, ptr, len)

src/bytes_mut.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,6 +1683,14 @@ unsafe impl crate::BytesImpl for SharedImpl {
16831683
(AtomicPtr::new(this.shared.cast()), this.ptr, this.len)
16841684
}
16851685

1686+
unsafe fn from_bytes_parts(data: &mut AtomicPtr<()>, ptr: *const u8, len: usize) -> Self {
1687+
SharedImpl {
1688+
shared: (data.with_mut(|p| *p)).cast(),
1689+
ptr,
1690+
len,
1691+
}
1692+
}
1693+
16861694
unsafe fn clone(data: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes {
16871695
let shared = data.load(Ordering::Relaxed) as *mut Shared;
16881696
increment_shared(shared);

0 commit comments

Comments
 (0)