Skip to content

Commit c55e4eb

Browse files
committed
glib: Add Bytes::into_data() and Bytes::from_bytes()` bindings
1 parent c940ecd commit c55e4eb

File tree

1 file changed

+73
-1
lines changed

1 file changed

+73
-1
lines changed

glib/src/bytes.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use std::{
55
cmp::Ordering,
66
fmt,
77
hash::{Hash, Hasher},
8-
ops::Deref,
8+
mem,
9+
ops::{Bound, Deref, RangeBounds},
910
slice,
1011
};
1112

@@ -64,6 +65,7 @@ impl Bytes {
6465

6566
// rustdoc-stripper-ignore-next
6667
/// Takes ownership of `data` and creates a new `Bytes` without copying.
68+
#[doc(alias = "g_bytes_new")]
6769
pub fn from_owned<T: AsRef<[u8]> + Send + 'static>(data: T) -> Bytes {
6870
let data: Box<T> = Box::new(data);
6971
let (size, data_ptr) = {
@@ -84,6 +86,56 @@ impl Bytes {
8486
))
8587
}
8688
}
89+
90+
// rustdoc-stripper-ignore-next
91+
/// Returns the underlying data of the `Bytes`.
92+
///
93+
/// If there is no other reference to `self` then this does not copy the data, otherwise
94+
/// it is copied into newly allocated heap memory.
95+
#[doc(alias = "g_bytes_unref_to_data")]
96+
pub fn into_data(self) -> crate::collections::Slice<u8> {
97+
unsafe {
98+
let mut size = mem::MaybeUninit::uninit();
99+
let ret = ffi::g_bytes_unref_to_data(self.into_glib_ptr(), size.as_mut_ptr());
100+
crate::collections::Slice::from_glib_full_num(ret as *mut u8, size.assume_init())
101+
}
102+
}
103+
104+
fn calculate_offset_size(&self, range: impl RangeBounds<usize>) -> (usize, usize) {
105+
let len = self.len();
106+
107+
let start_offset = match range.start_bound() {
108+
Bound::Included(v) => *v,
109+
Bound::Excluded(v) => v.checked_add(1).expect("Invalid start offset"),
110+
Bound::Unbounded => 0,
111+
};
112+
assert!(start_offset < len, "Start offset after valid range");
113+
114+
let end_offset = match range.end_bound() {
115+
Bound::Included(v) => v.checked_add(1).expect("Invalid end offset"),
116+
Bound::Excluded(v) => *v,
117+
Bound::Unbounded => len,
118+
};
119+
assert!(end_offset <= len, "End offset after valid range");
120+
121+
let size = end_offset.saturating_sub(start_offset);
122+
123+
(start_offset, size)
124+
}
125+
126+
// rustdoc-stripper-ignore-next
127+
/// Creates a new `Bytes` that references the given `range` of `bytes`.
128+
#[doc(alias = "g_bytes_new_from_bytes")]
129+
pub fn from_bytes(bytes: &Self, range: impl RangeBounds<usize>) -> Self {
130+
let (offset, size) = bytes.calculate_offset_size(range);
131+
unsafe {
132+
from_glib_full(ffi::g_bytes_new_from_bytes(
133+
bytes.to_glib_none().0,
134+
offset,
135+
size,
136+
))
137+
}
138+
}
87139
}
88140

89141
unsafe impl Send for Bytes {}
@@ -274,4 +326,24 @@ mod tests {
274326
let b = Bytes::from_owned(vec![1, 2, 3]);
275327
assert_eq!(b, [1u8, 2u8, 3u8].as_ref());
276328
}
329+
330+
#[test]
331+
fn from_bytes() {
332+
let b1 = Bytes::from_owned(vec![1, 2, 3]);
333+
let b2 = Bytes::from_bytes(&b1, 1..=1);
334+
assert_eq!(b2, [2u8].as_ref());
335+
let b2 = Bytes::from_bytes(&b1, 1..);
336+
assert_eq!(b2, [2u8, 3u8].as_ref());
337+
let b2 = Bytes::from_bytes(&b1, ..2);
338+
assert_eq!(b2, [1u8, 2u8].as_ref());
339+
let b2 = Bytes::from_bytes(&b1, ..);
340+
assert_eq!(b2, [1u8, 2u8, 3u8].as_ref());
341+
}
342+
343+
#[test]
344+
pub fn into_data() {
345+
let b = Bytes::from(b"this is a test");
346+
let d = b.into_data();
347+
assert_eq!(d.as_slice(), b"this is a test");
348+
}
277349
}

0 commit comments

Comments
 (0)