Skip to content

Commit 33d3499

Browse files
authored
Merge pull request #857 from sdroege/gstringbuilder-improvements
glib: Minor `GStringBuilder` improvements
2 parents 932f275 + 25cad90 commit 33d3499

File tree

2 files changed

+33
-22
lines changed

2 files changed

+33
-22
lines changed

glib/src/gstring.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,21 @@ impl GString {
440440
pub unsafe fn from_ptr_lossy<'a>(ptr: *const c_char) -> Cow<'a, GStr> {
441441
GStr::from_ptr_lossy(ptr)
442442
}
443+
444+
// rustdoc-stripper-ignore-next
445+
/// Wraps a raw C string with a safe GLib string wrapper. The provided C string **must** be
446+
/// nul-terminated. All constraints from [`std::ffi::CStr::from_ptr`] also apply here.
447+
///
448+
/// `len` is the length without the nul-terminator, i.e. if `len == 0` is passed then `*ptr`
449+
/// must be the nul-terminator.
450+
pub unsafe fn from_ptr_and_len_unchecked(ptr: *const c_char, len: usize) -> Self {
451+
assert!(!ptr.is_null());
452+
453+
GString(Inner::Foreign {
454+
ptr: ptr::NonNull::new_unchecked(ptr as *mut _),
455+
len,
456+
})
457+
}
443458
}
444459

445460
impl IntoGlibPtr<*mut c_char> for GString {

glib/src/gstring_builder.rs

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,25 @@ wrapper! {
2121
copy => |ptr| ffi::g_string_new((*ptr).str),
2222
free => |ptr| ffi::g_string_free(ptr, ffi::GTRUE),
2323
init => |ptr| unsafe {
24-
*ptr = ffi::GString {
25-
str: ffi::g_malloc0(64) as *mut _,
24+
let inner = ffi::GString {
25+
str: ffi::g_malloc(64) as *mut _,
2626
len: 0,
2727
allocated_len: 64,
2828
};
29+
ptr::write(inner.str, 0);
30+
31+
*ptr = inner;
2932
},
3033
copy_into => |dest, src| {
34+
assert!((*src).allocated_len > (*src).len);
3135
let allocated_len = (*src).allocated_len;
32-
let mut inner = ffi::GString {
33-
str: ffi::g_malloc0(allocated_len) as *mut _,
36+
let inner = ffi::GString {
37+
str: ffi::g_malloc(allocated_len) as *mut _,
3438
len: 0,
3539
allocated_len,
3640
};
37-
ffi::g_string_append_len(&mut inner, (*src).str, (*src).len as isize);
41+
// +1 to also copy the NUL-terminator
42+
ptr::copy_nonoverlapping((*src).str, inner.str, (*src).len + 1);
3843
*dest = inner;
3944
},
4045
clear => |ptr| {
@@ -56,19 +61,16 @@ impl GStringBuilder {
5661
let allocated_len = usize::next_power_of_two(std::cmp::max(data.len(), 64) + 1);
5762
assert_ne!(allocated_len, 0);
5863

59-
let mut inner = ffi::GString {
64+
let inner = ffi::GString {
6065
str: ffi::g_malloc(allocated_len) as *mut _,
61-
len: 0,
66+
len: data.len(),
6267
allocated_len,
6368
};
6469
if data.is_empty() {
6570
ptr::write(inner.str, 0);
6671
} else {
67-
ffi::g_string_append_len(
68-
&mut inner,
69-
data.as_ptr() as *const _,
70-
data.len() as isize,
71-
);
72+
ptr::copy_nonoverlapping(data.as_ptr() as *const _, inner.str, data.len());
73+
ptr::write(inner.str.add(data.len()), 0);
7274
}
7375
Self { inner }
7476
}
@@ -116,10 +118,6 @@ impl GStringBuilder {
116118

117119
// rustdoc-stripper-ignore-next
118120
/// Returns `&str` slice.
119-
///
120-
/// # Panics
121-
///
122-
/// If the string builder contains invalid UTF-8 this function panics.
123121
pub fn as_str(&self) -> &str {
124122
unsafe {
125123
let ptr: *const u8 = self.inner.str as _;
@@ -128,21 +126,17 @@ impl GStringBuilder {
128126
return "";
129127
}
130128
let slice = slice::from_raw_parts(ptr, len);
131-
std::str::from_utf8(slice).unwrap()
129+
std::str::from_utf8_unchecked(slice)
132130
}
133131
}
134132

135133
// rustdoc-stripper-ignore-next
136134
/// Returns `&str` slice.
137-
///
138-
/// # Panics
139-
///
140-
/// If the string builder contains invalid UTF-8 this function panics.
141135
#[must_use = "String returned from the builder should probably be used"]
142136
pub fn into_string(self) -> crate::GString {
143137
unsafe {
144138
let s = mem::ManuallyDrop::new(self);
145-
crate::GString::from_glib_full_num(s.inner.str, s.inner.len)
139+
crate::GString::from_ptr_and_len_unchecked(s.inner.str, s.inner.len)
146140
}
147141
}
148142
}
@@ -257,6 +251,7 @@ mod tests {
257251
#[test]
258252
fn append() {
259253
let mut s = crate::GStringBuilder::new("");
254+
assert_eq!(&*s, "");
260255
s.append("Hello");
261256
s.append(" ");
262257
s.append("there!");
@@ -267,6 +262,7 @@ mod tests {
267262
#[test]
268263
fn prepend() {
269264
let mut s = crate::GStringBuilder::new("456");
265+
assert_eq!(&*s, "456");
270266
s.prepend("123");
271267
assert_eq!(&*s, "123456");
272268
}

0 commit comments

Comments
 (0)