Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

glib: Add various IntoStrV impls #977

Merged
merged 1 commit into from Feb 10, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
159 changes: 147 additions & 12 deletions glib/src/collections/strv.rs
Expand Up @@ -1054,31 +1054,121 @@ const MAX_STACK_ALLOCATION: usize = 16;
impl IntoStrV for Vec<GString> {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
+ self.iter().map(|s| s.len() + 1).sum::<usize>();
self.as_slice().run_with_strv(f)
}
}

impl<'a> IntoStrV for Vec<&'a GString> {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
self.as_slice().run_with_strv(f)
}
}

impl<'a> IntoStrV for Vec<&'a GStr> {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
self.as_slice().run_with_strv(f)
}
}

impl<'a> IntoStrV for Vec<&'a str> {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
self.as_slice().run_with_strv(f)
}
}

impl IntoStrV for Vec<String> {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
self.as_slice().run_with_strv(f)
}
}

impl<'a> IntoStrV for Vec<&'a String> {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
self.as_slice().run_with_strv(f)
}
}

impl IntoStrV for &[GString] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();

if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
unsafe {
let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
let ptrs = s.as_mut_ptr() as *mut *mut c_char;
let mut strs = ptrs.add(self.len() + 1) as *mut c_char;

for (i, item) in self.iter().enumerate() {
ptr::copy_nonoverlapping(item.as_ptr(), strs, item.len() + 1);
*ptrs.add(i) = strs;
strs = strs.add(item.len() + 1);
*ptrs.add(i) = item.as_ptr() as *mut _;
}
*ptrs.add(self.len()) = ptr::null_mut();

f(std::slice::from_raw_parts(ptrs, self.len() + 1))
}
} else {
let mut s = StrV::with_capacity(self.len());
s.extend_from_slice(self);
s.run_with_strv(f)
}
}
}

impl<'a> IntoStrV for &[&'a GString] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();

if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
unsafe {
let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
let ptrs = s.as_mut_ptr() as *mut *mut c_char;

for (i, item) in self.iter().enumerate() {
*ptrs.add(i) = item.as_ptr() as *mut _;
}
*ptrs.add(self.len()) = ptr::null_mut();

f(std::slice::from_raw_parts(ptrs, self.len() + 1))
}
} else {
StrV::from(self).run_with_strv(f)
let mut s = StrV::with_capacity(self.len());
s.extend_from_slice(self);
s.run_with_strv(f)
}
}
}

impl<'a> IntoStrV for &'a [String] {
impl<'a> IntoStrV for &[&'a GStr] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();

if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
unsafe {
let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
let ptrs = s.as_mut_ptr() as *mut *mut c_char;

for (i, item) in self.iter().enumerate() {
*ptrs.add(i) = item.as_ptr() as *mut _;
}
*ptrs.add(self.len()) = ptr::null_mut();

f(std::slice::from_raw_parts(ptrs, self.len() + 1))
}
} else {
let mut s = StrV::with_capacity(self.len());
s.extend_from_slice(self);
s.run_with_strv(f)
}
}
}

impl<'a> IntoStrV for &[&'a str] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
Expand Down Expand Up @@ -1108,7 +1198,7 @@ impl<'a> IntoStrV for &'a [String] {
}
}

impl<'a> IntoStrV for &'a [&'a str] {
impl IntoStrV for &[String] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
Expand Down Expand Up @@ -1138,7 +1228,7 @@ impl<'a> IntoStrV for &'a [&'a str] {
}
}

impl<const N: usize> IntoStrV for [GString; N] {
impl<'a> IntoStrV for &[&'a String] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
Expand All @@ -1151,7 +1241,8 @@ impl<const N: usize> IntoStrV for [GString; N] {
let mut strs = ptrs.add(self.len() + 1) as *mut c_char;

for (i, item) in self.iter().enumerate() {
ptr::copy_nonoverlapping(item.as_ptr(), strs, item.len() + 1);
ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
*strs.add(item.len()) = 0;
*ptrs.add(i) = strs;
strs = strs.add(item.len() + 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we care about alignment?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

char arrays have an alignment of 1 so that's fine here. But that's exactly why the pointers come first and afterwards the characters :)

}
Expand All @@ -1160,11 +1251,55 @@ impl<const N: usize> IntoStrV for [GString; N] {
f(std::slice::from_raw_parts(ptrs, self.len() + 1))
}
} else {
StrV::from(self).run_with_strv(f)
let mut s = StrV::with_capacity(self.len());
s.extend_from_slice(self);
s.run_with_strv(f)
}
}
}

impl<const N: usize> IntoStrV for [GString; N] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
self.as_slice().run_with_strv(f)
}
}

impl<'a, const N: usize> IntoStrV for [&'a GString; N] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
self.as_slice().run_with_strv(f)
}
}

impl<'a, const N: usize> IntoStrV for [&'a GStr; N] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
self.as_slice().run_with_strv(f)
}
}

impl<'a, const N: usize> IntoStrV for [&'a str; N] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
self.as_slice().run_with_strv(f)
}
}

impl<const N: usize> IntoStrV for [String; N] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
self.as_slice().run_with_strv(f)
}
}

impl<'a, const N: usize> IntoStrV for [&'a String; N] {
#[inline]
fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
self.as_slice().run_with_strv(f)
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down