Skip to content

Commit 932f275

Browse files
authored
Merge pull request #856 from sdroege/gstringbuilder-noalloc
glib: Implement `GStringBuilder` as `BoxedInline` to avoid a useless …
2 parents de6029b + 535f575 commit 932f275

File tree

1 file changed

+44
-12
lines changed

1 file changed

+44
-12
lines changed

glib/src/gstring_builder.rs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,31 @@ wrapper! {
1515
/// A mutable text buffer that grows automatically.
1616
#[doc(alias = "GString")]
1717
#[must_use = "The builder must be built to be used"]
18-
pub struct GStringBuilder(Boxed<ffi::GString>);
18+
pub struct GStringBuilder(BoxedInline<ffi::GString>);
1919

2020
match fn {
2121
copy => |ptr| ffi::g_string_new((*ptr).str),
2222
free => |ptr| ffi::g_string_free(ptr, ffi::GTRUE),
23+
init => |ptr| unsafe {
24+
*ptr = ffi::GString {
25+
str: ffi::g_malloc0(64) as *mut _,
26+
len: 0,
27+
allocated_len: 64,
28+
};
29+
},
30+
copy_into => |dest, src| {
31+
let allocated_len = (*src).allocated_len;
32+
let mut inner = ffi::GString {
33+
str: ffi::g_malloc0(allocated_len) as *mut _,
34+
len: 0,
35+
allocated_len,
36+
};
37+
ffi::g_string_append_len(&mut inner, (*src).str, (*src).len as isize);
38+
*dest = inner;
39+
},
40+
clear => |ptr| {
41+
ffi::g_free((*ptr).str as *mut _);
42+
},
2343
type_ => || ffi::g_gstring_get_type(),
2444
}
2545
}
@@ -29,13 +49,28 @@ unsafe impl Sync for GStringBuilder {}
2949

3050
impl GStringBuilder {
3151
#[doc(alias = "g_string_new_len")]
32-
pub fn new<T: AsRef<[u8]>>(data: T) -> GStringBuilder {
33-
let bytes = data.as_ref();
52+
pub fn new<T: AsRef<str>>(data: T) -> GStringBuilder {
53+
let data = data.as_ref();
54+
assert!(data.len() < usize::MAX - 1);
3455
unsafe {
35-
from_glib_full(ffi::g_string_new_len(
36-
bytes.as_ptr() as *const _,
37-
bytes.len() as isize,
38-
))
56+
let allocated_len = usize::next_power_of_two(std::cmp::max(data.len(), 64) + 1);
57+
assert_ne!(allocated_len, 0);
58+
59+
let mut inner = ffi::GString {
60+
str: ffi::g_malloc(allocated_len) as *mut _,
61+
len: 0,
62+
allocated_len,
63+
};
64+
if data.is_empty() {
65+
ptr::write(inner.str, 0);
66+
} else {
67+
ffi::g_string_append_len(
68+
&mut inner,
69+
data.as_ptr() as *const _,
70+
data.len() as isize,
71+
);
72+
}
73+
Self { inner }
3974
}
4075
}
4176

@@ -107,10 +142,7 @@ impl GStringBuilder {
107142
pub fn into_string(self) -> crate::GString {
108143
unsafe {
109144
let s = mem::ManuallyDrop::new(self);
110-
from_glib_full(ffi::g_string_free(
111-
mut_override(s.to_glib_none().0),
112-
ffi::GFALSE,
113-
))
145+
crate::GString::from_glib_full_num(s.inner.str, s.inner.len)
114146
}
115147
}
116148
}
@@ -119,7 +151,7 @@ impl Default for GStringBuilder {
119151
// rustdoc-stripper-ignore-next
120152
/// Creates a new empty string.
121153
fn default() -> Self {
122-
unsafe { from_glib_full(ffi::g_string_new(ptr::null())) }
154+
Self::new("")
123155
}
124156
}
125157

0 commit comments

Comments
 (0)