Skip to content

Commit b6c7b55

Browse files
authored
Merge branch 'main' into gyuheon0h/prof-12743-cp-ffi
2 parents b0fff2e + c4cdaa2 commit b6c7b55

File tree

4 files changed

+65
-44
lines changed

4 files changed

+65
-44
lines changed

datadog-trace-utils/src/msgpack_decoder/v04/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ use crate::span::{SpanBytes, SpanSlice};
5050
/// assert_eq!("test-span", decoded_span.name.as_str());
5151
/// ```
5252
pub fn from_bytes(data: tinybytes::Bytes) -> Result<(Vec<Vec<SpanBytes>>, usize), DecodeError> {
53-
let mut parsed_data = data.clone();
54-
let (traces_ref, size) = from_slice(unsafe { parsed_data.as_mut_slice() })?;
53+
let (traces_ref, size) = from_slice(data.as_ref())?;
5554

5655
#[allow(clippy::unwrap_used)]
5756
let traces_owned = traces_ref

datadog-trace-utils/src/msgpack_decoder/v05/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,7 @@ const SPAN_ELEM_COUNT: u32 = 12;
6868
/// assert_eq!("", decoded_span.name.as_str());
6969
/// ```
7070
pub fn from_bytes(data: tinybytes::Bytes) -> Result<(Vec<Vec<SpanBytes>>, usize), DecodeError> {
71-
let mut parsed_data = data.clone();
72-
let (traces_ref, size) = from_slice(unsafe { parsed_data.as_mut_slice() })?;
71+
let (traces_ref, size) = from_slice(data.as_ref())?;
7372

7473
#[allow(clippy::unwrap_used)]
7574
let traces_owned = traces_ref

tinybytes/src/lib.rs

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use serde::Serialize;
2020
/// Immutable bytes type with zero copy cloning and slicing.
2121
#[derive(Clone)]
2222
pub struct Bytes {
23-
slice: &'static [u8],
23+
ptr: NonNull<u8>,
24+
len: usize,
2425
// The `bytes`` field is used to ensure that the underlying bytes are freed when there are no
2526
// more references to the `Bytes` object. For static buffers the field is `None`.
2627
bytes: Option<RefCountedCell>,
@@ -48,10 +49,9 @@ impl Bytes {
4849
len: usize,
4950
refcount: RefCountedCell,
5051
) -> Self {
51-
// SAFETY: The caller must ensure that the pointer is valid and that the length is correct.
52-
let slice = unsafe { std::slice::from_raw_parts(ptr.as_ptr(), len) };
5352
Self {
54-
slice,
53+
ptr,
54+
len,
5555
bytes: Some(refcount),
5656
}
5757
}
@@ -65,8 +65,12 @@ impl Bytes {
6565
/// Creates `Bytes` from a static slice.
6666
#[inline]
6767
pub const fn from_static(value: &'static [u8]) -> Self {
68-
let slice: &[u8] = value;
69-
Self { slice, bytes: None }
68+
Self {
69+
// SAFETY: static slice always have a valid pointer and length
70+
ptr: unsafe { NonNull::new_unchecked(value.as_ptr().cast_mut()) },
71+
len: value.len(),
72+
bytes: None,
73+
}
7074
}
7175

7276
/// Creates `Bytes` from a slice, by copying.
@@ -77,13 +81,13 @@ impl Bytes {
7781
/// Returns the length of the `Bytes`.
7882
#[inline]
7983
pub const fn len(&self) -> usize {
80-
self.slice.len()
84+
self.len
8185
}
8286

8387
/// Returns `true` if the `Bytes` is empty.
8488
#[inline]
8589
pub const fn is_empty(&self) -> bool {
86-
self.slice.is_empty()
90+
self.len == 0
8791
}
8892

8993
/// Returns a slice of self for the provided range.
@@ -178,54 +182,58 @@ impl Bytes {
178182

179183
let subset_start = subset.as_ptr() as usize;
180184
let subset_end = subset_start + subset.len();
181-
let self_start = self.slice.as_ptr() as usize;
182-
let self_end = self_start + self.slice.len();
185+
let self_start = self.ptr.as_ptr() as usize;
186+
let self_end = self_start + self.len;
183187
if subset_start >= self_start && subset_end <= self_end {
184188
Some(self.safe_slice_ref(subset_start - self_start, subset_end - self_start))
185189
} else {
186190
None
187191
}
188192
}
189193

190-
/// Returns a mutable reference to the slice of self.
191-
/// Allows for fast unchecked shrinking of the slice.
192-
///
193-
/// # Safety
194-
///
195-
/// Callers of that function must make sure that they only put subslices of the slice into the
196-
/// returned reference.
197-
/// They also need to make sure to not persist the slice reference for longer than the struct
198-
/// lives.
199-
#[inline]
200-
pub unsafe fn as_mut_slice(&mut self) -> &mut &'static [u8] {
201-
&mut self.slice
202-
}
203-
204-
pub fn from_underlying(value: impl UnderlyingBytes) -> Self {
194+
pub fn from_underlying<T: UnderlyingBytes>(value: T) -> Self {
205195
unsafe {
196+
let refcounted = make_refcounted(value);
197+
let a = refcounted.data.cast::<CustomArc<T>>().as_ptr();
198+
206199
// SAFETY:
207200
// * the pointer associated with a slice is non null and valid for the length of the
208201
// slice
209-
// * it stays valid as long as value is not dopped
202+
// * it stays valid as long as value is not dropped
203+
let data: &T = &(*a).data;
210204
let (ptr, len) = {
211-
let s = value.as_ref();
205+
let s = data.as_ref();
212206
(NonNull::new_unchecked(s.as_ptr().cast_mut()), s.len())
213207
};
214-
Self::from_raw_refcount(ptr, len, make_refcounted(value))
208+
Self::from_raw_refcount(ptr, len, refcounted)
215209
}
216210
}
217211

218212
#[inline]
219213
fn safe_slice_ref(&self, start: usize, end: usize) -> Self {
214+
if !(start <= end && end <= self.len) {
215+
#[allow(clippy::panic)]
216+
{
217+
panic!("Out of bound slicing of Bytes instance")
218+
}
219+
}
220+
// SAFETY:
221+
// * start is less than len, so the resulting pointer is
222+
// going either inside the allocation or one past
223+
// * we have 0 <= start <= end <= len so 0 <= end - start <= len - start. Since the new ptr
224+
// points to ptr + start, then memory span is between ptr + start and (ptr + start) + (len -
225+
// start) = ptr + len
220226
Self {
221-
slice: &self.slice[start..end],
227+
ptr: unsafe { self.ptr.add(start) },
228+
len: end - start,
222229
bytes: self.bytes.clone(),
223230
}
224231
}
225232

226233
#[inline]
227234
fn as_slice(&self) -> &[u8] {
228-
self.slice
235+
// SAFETY: ptr is valid for the associated length
236+
unsafe { std::slice::from_raw_parts(self.ptr.as_ptr().cast_const(), self.len()) }
229237
}
230238
}
231239

@@ -357,21 +365,21 @@ pub struct RefCountedCellVTable {
357365
pub drop: unsafe fn(NonNull<()>),
358366
}
359367

368+
/// A custom Arc implementation that contains only the strong count
369+
///
370+
/// This struct is not exposed to the outside of this functions and is
371+
/// only interacted with through the `RefCountedCell` API.
372+
struct CustomArc<T> {
373+
rc: AtomicUsize,
374+
#[allow(unused)]
375+
data: T,
376+
}
377+
360378
/// Creates a refcounted cell.
361379
///
362380
/// The data passed to this cell will only be dopped when the last
363381
/// clone of the cell is dropped.
364382
fn make_refcounted<T: Send + Sync + 'static>(data: T) -> RefCountedCell {
365-
/// A custom Arc implementation that contains only the strong count
366-
///
367-
/// This struct is not exposed to the outside of this functions and is
368-
/// only interacted with through the `RefCountedCell` API.
369-
struct CustomArc<T> {
370-
rc: AtomicUsize,
371-
#[allow(unused)]
372-
data: T,
373-
}
374-
375383
unsafe fn custom_arc_clone<T>(data: NonNull<()>) -> RefCountedCell {
376384
let custom_arc = data.cast::<CustomArc<T>>().as_ref();
377385
custom_arc

tinybytes/src/test.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use core::str;
5+
use std::hint::black_box;
56
use std::sync::atomic::{self, AtomicUsize};
67
use std::sync::Arc;
78

@@ -22,6 +23,20 @@ fn hello_slice(range: impl RangeBounds<usize>) -> Bytes {
2223
hello().slice(range)
2324
}
2425

26+
#[test]
27+
fn test_from_underlying_vec() {
28+
let b = Bytes::from_underlying(vec![1, 2, 3]);
29+
let b1 = b.clone();
30+
for i in b1.as_slice() {
31+
black_box(i);
32+
}
33+
for i in b.as_slice() {
34+
black_box(i);
35+
}
36+
drop(b);
37+
drop(b1);
38+
}
39+
2540
#[test]
2641
fn test_make_refcounted() {
2742
let data = vec![1, 2, 3];

0 commit comments

Comments
 (0)