| ... | @@ -17,10 +17,12 @@ use std::ptr; |
... | @@ -17,10 +17,12 @@ use std::ptr; |
|
|
use std::ffi::CStr;
|
|
use std::ffi::CStr;
|
|
|
|
|
|
|
|
use libc::c_char;
|
|
use libc::c_char;
|
|
|
use libc::calloc;
|
|
|
|
|
use libc::free;
|
|
|
|
|
|
|
|
|
|
use crate::buffer::rust_str_to_c_str;
|
|
use crate::ffi::MM;
|
|
|
|
use crate::buffer::{
|
|
|
|
malloc_cleared,
|
|
|
|
rust_str_to_c_str,
|
|
|
|
};
|
|
|
|
|
|
|
|
#[repr(C)]
|
|
#[repr(C)]
|
|
|
pub struct StringListItem {
|
|
pub struct StringListItem {
|
| ... | @@ -33,11 +35,12 @@ impl StringListItem { |
... | @@ -33,11 +35,12 @@ impl StringListItem { |
|
|
///
|
|
///
|
|
|
/// The memory is allocated using the libc allocator. The caller
|
|
/// The memory is allocated using the libc allocator. The caller
|
|
|
/// is responsible for freeing it explicitly.
|
|
/// is responsible for freeing it explicitly.
|
|
|
fn empty() -> &'static mut Self {
|
|
fn empty(mm: MM) -> &'static mut Self {
|
|
|
let buffer = unsafe { calloc(1, std::mem::size_of::<Self>()) };
|
|
let buffer = if let Ok(buffer) = malloc_cleared::<Self>(mm) {
|
|
|
if buffer.is_null() {
|
|
buffer
|
|
|
|
} else {
|
|
|
panic!("Out of memory allocating a StringListItem");
|
|
panic!("Out of memory allocating a StringListItem");
|
|
|
}
|
|
};
|
|
|
unsafe { &mut *(buffer as *mut Self) }
|
|
unsafe { &mut *(buffer as *mut Self) }
|
|
|
}
|
|
}
|
|
|
|
|
|
| ... | @@ -46,10 +49,10 @@ impl StringListItem { |
... | @@ -46,10 +49,10 @@ impl StringListItem { |
|
|
///
|
|
///
|
|
|
/// The memory is allocated using the libc allocator. The caller
|
|
/// The memory is allocated using the libc allocator. The caller
|
|
|
/// is responsible for freeing it explicitly.
|
|
/// is responsible for freeing it explicitly.
|
|
|
fn new<S: AsRef<str>>(value: S, next: *mut Self) -> &'static mut Self {
|
|
fn new<S: AsRef<str>>(mm: MM, value: S, next: *mut Self) -> &'static mut Self {
|
|
|
let item = Self::empty();
|
|
let item = Self::empty(mm);
|
|
|
|
|
|
|
|
item.value = rust_str_to_c_str(value);
|
|
item.value = rust_str_to_c_str(mm, value);
|
|
|
item.next = next;
|
|
item.next = next;
|
|
|
|
|
|
|
|
item
|
|
item
|
| ... | @@ -69,6 +72,7 @@ pub struct StringList { |
... | @@ -69,6 +72,7 @@ pub struct StringList { |
|
|
head: *mut StringListItem,
|
|
head: *mut StringListItem,
|
|
|
// If set, when the StringList is dropped, the items are freed.
|
|
// If set, when the StringList is dropped, the items are freed.
|
|
|
owned: bool,
|
|
owned: bool,
|
|
|
|
mm: MM,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
impl StringList {
|
|
impl StringList {
|
| ... | @@ -77,10 +81,12 @@ impl StringList { |
... | @@ -77,10 +81,12 @@ impl StringList { |
|
|
/// `owned` indicates whether the rust code should own the items.
|
|
/// `owned` indicates whether the rust code should own the items.
|
|
|
/// If so, when the `StringList` is dropped, the items will also
|
|
/// If so, when the `StringList` is dropped, the items will also
|
|
|
/// be freed.
|
|
/// be freed.
|
|
|
pub fn to_rust(sl: *mut StringListItem, owned: bool) -> Self {
|
|
pub fn to_rust(mm: MM, sl: *mut StringListItem, owned: bool) -> Self
|
|
|
|
{
|
|
|
StringList {
|
|
StringList {
|
|
|
head: sl,
|
|
head: sl,
|
|
|
owned,
|
|
owned,
|
|
|
|
mm,
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
| ... | @@ -97,10 +103,11 @@ impl StringList { |
... | @@ -97,10 +103,11 @@ impl StringList { |
|
|
/// The items are owned by the `StringList`, and when it is
|
|
/// The items are owned by the `StringList`, and when it is
|
|
|
/// dropped, they are freed. To take ownership of the items, call
|
|
/// dropped, they are freed. To take ownership of the items, call
|
|
|
/// `StringList::to_c`.
|
|
/// `StringList::to_c`.
|
|
|
pub fn new<S: AsRef<str>>(value: S) -> Self {
|
|
pub fn new<S: AsRef<str>>(mm: MM, value: S) -> Self {
|
|
|
StringList {
|
|
StringList {
|
|
|
head: StringListItem::new(value, ptr::null_mut()),
|
|
head: StringListItem::new(mm, value, ptr::null_mut()),
|
|
|
owned: true,
|
|
owned: true,
|
|
|
|
mm,
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
| ... | @@ -109,10 +116,12 @@ impl StringList { |
... | @@ -109,10 +116,12 @@ impl StringList { |
|
|
/// Any added items are owned by the `StringList`, and when it is
|
|
/// Any added items are owned by the `StringList`, and when it is
|
|
|
/// dropped, they are freed. To take ownership of the items, call
|
|
/// dropped, they are freed. To take ownership of the items, call
|
|
|
/// `StringList::to_c`.
|
|
/// `StringList::to_c`.
|
|
|
pub fn empty() -> Self {
|
|
pub fn empty(mm: MM) -> Self
|
|
|
|
{
|
|
|
StringList {
|
|
StringList {
|
|
|
head: ptr::null_mut(),
|
|
head: ptr::null_mut(),
|
|
|
owned: true,
|
|
owned: true,
|
|
|
|
mm,
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
| ... | @@ -121,9 +130,12 @@ impl StringList { |
... | @@ -121,9 +130,12 @@ impl StringList { |
|
|
/// variant, which we use for testing.
|
|
/// variant, which we use for testing.
|
|
|
#[cfg(test)]
|
|
#[cfg(test)]
|
|
|
fn empty_alt() -> Self {
|
|
fn empty_alt() -> Self {
|
|
|
|
let mm = MM { malloc: libc::malloc, free: libc::free };
|
|
|
|
|
|
|
StringList {
|
|
StringList {
|
|
|
head: StringListItem::empty(),
|
|
head: StringListItem::empty(mm),
|
|
|
owned: true,
|
|
owned: true,
|
|
|
|
mm,
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
| ... | @@ -147,6 +159,8 @@ impl StringList { |
... | @@ -147,6 +159,8 @@ impl StringList { |
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn add_<S: AsRef<str>>(&mut self, value: S, dedup: bool) {
|
|
fn add_<S: AsRef<str>>(&mut self, value: S, dedup: bool) {
|
|
|
|
let mm = self.mm;
|
|
|
|
|
|
|
let value = value.as_ref();
|
|
let value = value.as_ref();
|
|
|
|
|
|
|
|
// See if the value already exists in the string list.
|
|
// See if the value already exists in the string list.
|
| ... | @@ -163,18 +177,18 @@ impl StringList { |
... | @@ -163,18 +177,18 @@ impl StringList { |
|
|
let itemp = iter.item();
|
|
let itemp = iter.item();
|
|
|
if (*itemp).is_null() {
|
|
if (*itemp).is_null() {
|
|
|
// 1. head is NULL (this is the case if item is NULL).
|
|
// 1. head is NULL (this is the case if item is NULL).
|
|
|
*itemp = StringListItem::new(value, ptr::null_mut());
|
|
*itemp = StringListItem::new(mm, value, ptr::null_mut());
|
|
|
} else {
|
|
} else {
|
|
|
let item: &mut StringListItem
|
|
let item: &mut StringListItem
|
|
|
= StringListItem::as_mut(*itemp).expect("just checked");
|
|
= StringListItem::as_mut(*itemp).expect("just checked");
|
|
|
|
|
|
|
|
if item.value.is_null() {
|
|
if item.value.is_null() {
|
|
|
// 2. head is not NULL, but head.value is NULL.
|
|
// 2. head is not NULL, but head.value is NULL.
|
|
|
item.value = rust_str_to_c_str(value);
|
|
item.value = rust_str_to_c_str(mm, value);
|
|
|
} else {
|
|
} else {
|
|
|
// 3. neither head nor head.value are NULL.
|
|
// 3. neither head nor head.value are NULL.
|
|
|
assert!(item.next.is_null());
|
|
assert!(item.next.is_null());
|
|
|
item.next = StringListItem::new(value, ptr::null_mut());
|
|
item.next = StringListItem::new(mm, value, ptr::null_mut());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
| ... | @@ -200,6 +214,8 @@ impl StringList { |
... | @@ -200,6 +214,8 @@ impl StringList { |
|
|
/// The items in other have the same ownership as items in `self`.
|
|
/// The items in other have the same ownership as items in `self`.
|
|
|
/// `other` is reset to an empty list.
|
|
/// `other` is reset to an empty list.
|
|
|
pub fn append(&mut self, other: &mut StringList) {
|
|
pub fn append(&mut self, other: &mut StringList) {
|
|
|
|
let free = self.mm.free;
|
|
|
|
|
|
|
let mut iter = self.iter_mut();
|
|
let mut iter = self.iter_mut();
|
|
|
(&mut iter).last();
|
|
(&mut iter).last();
|
|
|
|
|
|
| ... | @@ -229,6 +245,8 @@ impl StringList { |
... | @@ -229,6 +245,8 @@ impl StringList { |
|
|
|
|
|
|
|
impl Drop for StringList {
|
|
impl Drop for StringList {
|
|
|
fn drop(&mut self) {
|
|
fn drop(&mut self) {
|
|
|
|
let free = self.mm.free;
|
|
|
|
|
|
|
let mut curr: *mut StringListItem = self.head;
|
|
let mut curr: *mut StringListItem = self.head;
|
|
|
self.head = ptr::null_mut();
|
|
self.head = ptr::null_mut();
|
|
|
|
|
|
| ... | @@ -320,27 +338,33 @@ mod tests { |
... | @@ -320,27 +338,33 @@ mod tests { |
|
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
|
fn empty() {
|
|
fn empty() {
|
|
|
|
let mm = MM { malloc: libc::malloc, free: libc::free };
|
|
|
|
|
|
|
// There are two ways to make an empty list. Either head is
|
|
// There are two ways to make an empty list. Either head is
|
|
|
// NULL or the string list item's value and next are NULL.
|
|
// NULL or the string list item's value and next are NULL.
|
|
|
let empty = StringList {
|
|
let empty = StringList {
|
|
|
head: ptr::null_mut(),
|
|
head: ptr::null_mut(),
|
|
|
owned: true,
|
|
owned: true,
|
|
|
|
mm: mm,
|
|
|
};
|
|
};
|
|
|
assert_eq!(empty.len(), 0);
|
|
assert_eq!(empty.len(), 0);
|
|
|
|
|
|
|
|
let empty = StringList {
|
|
let empty = StringList {
|
|
|
head: StringListItem::empty(),
|
|
head: StringListItem::empty(mm),
|
|
|
owned: true,
|
|
owned: true,
|
|
|
|
mm: mm,
|
|
|
};
|
|
};
|
|
|
assert_eq!(empty.len(), 0);
|
|
assert_eq!(empty.len(), 0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
|
fn add() {
|
|
fn add() {
|
|
|
|
let mm = MM { malloc: libc::malloc, free: libc::free };
|
|
|
|
|
|
|
for variant in 0..3 {
|
|
for variant in 0..3 {
|
|
|
let (mut list, mut v) = match variant {
|
|
let (mut list, mut v) = match variant {
|
|
|
0 => {
|
|
0 => {
|
|
|
let list = StringList::new("abc");
|
|
let list = StringList::new(mm, "abc");
|
|
|
assert_eq!(list.len(), 1);
|
|
assert_eq!(list.len(), 1);
|
|
|
|
|
|
|
|
let mut v: Vec<String> = Vec::new();
|
|
let mut v: Vec<String> = Vec::new();
|
| ... | @@ -348,7 +372,7 @@ mod tests { |
... | @@ -348,7 +372,7 @@ mod tests { |
|
|
|
|
|
|
|
(list, v)
|
|
(list, v)
|
|
|
},
|
|
},
|
|
|
1 => (StringList::empty(), Vec::new()),
|
|
1 => (StringList::empty(mm), Vec::new()),
|
|
|
2 => (StringList::empty_alt(), Vec::new()),
|
|
2 => (StringList::empty_alt(), Vec::new()),
|
|
|
_ => unreachable!(),
|
|
_ => unreachable!(),
|
|
|
};
|
|
};
|
| ... | @@ -374,10 +398,12 @@ mod tests { |
... | @@ -374,10 +398,12 @@ mod tests { |
|
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
|
fn add_unique() {
|
|
fn add_unique() {
|
|
|
|
let mm = MM { malloc: libc::malloc, free: libc::free };
|
|
|
|
|
|
|
for variant in 0..3 {
|
|
for variant in 0..3 {
|
|
|
let (mut list, mut v) = match variant {
|
|
let (mut list, mut v) = match variant {
|
|
|
0 => {
|
|
0 => {
|
|
|
let list = StringList::new("abc");
|
|
let list = StringList::new(mm, "abc");
|
|
|
assert_eq!(list.len(), 1);
|
|
assert_eq!(list.len(), 1);
|
|
|
|
|
|
|
|
let mut v: Vec<String> = Vec::new();
|
|
let mut v: Vec<String> = Vec::new();
|
| ... | @@ -385,7 +411,7 @@ mod tests { |
... | @@ -385,7 +411,7 @@ mod tests { |
|
|
|
|
|
|
|
(list, v)
|
|
(list, v)
|
|
|
},
|
|
},
|
|
|
1 => (StringList::empty(), Vec::new()),
|
|
1 => (StringList::empty(mm), Vec::new()),
|
|
|
2 => (StringList::empty_alt(), Vec::new()),
|
|
2 => (StringList::empty_alt(), Vec::new()),
|
|
|
_ => unreachable!(),
|
|
_ => unreachable!(),
|
|
|
};
|
|
};
|
| ... | @@ -420,12 +446,14 @@ mod tests { |
... | @@ -420,12 +446,14 @@ mod tests { |
|
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
|
fn append() {
|
|
fn append() {
|
|
|
|
let mm = MM { malloc: libc::malloc, free: libc::free };
|
|
|
|
|
|
|
for variant in 0..2 {
|
|
for variant in 0..2 {
|
|
|
// Returns a list and a vector with `count` items whose
|
|
// Returns a list and a vector with `count` items whose
|
|
|
// values are `prefix_0`, `prefix_1`, etc.
|
|
// values are `prefix_0`, `prefix_1`, etc.
|
|
|
let list = |count: usize, prefix: &str| -> (StringList, Vec<String>) {
|
|
let list = |count: usize, prefix: &str| -> (StringList, Vec<String>) {
|
|
|
let mut l = match variant {
|
|
let mut l = match variant {
|
|
|
0 => StringList::empty(),
|
|
0 => StringList::empty(mm),
|
|
|
1 => StringList::empty_alt(),
|
|
1 => StringList::empty_alt(),
|
|
|
_ => unreachable!(),
|
|
_ => unreachable!(),
|
|
|
};
|
|
};
|
| ... | | ... | |