forked from vitrine/wmaker
Replace WUtil hashtable with a Rust impl.
This tweaks the hashtable API, and it is incomplete because the WUtil proplist impl depends heavily on a feature of the old API that is being discontinued. Moving the proplist code into Rust is our next objective.
This commit is contained in:
@@ -20,6 +20,7 @@ libWUtil_la_LIBADD = @LIBBSD@ $(wutilrs)
|
||||
EXTRA_DIST = BUGS make-rgb Examples Extras Tests
|
||||
|
||||
|
||||
|
||||
# wbutton.c
|
||||
libWINGs_la_SOURCES = \
|
||||
configuration.c \
|
||||
@@ -69,7 +70,6 @@ libWUtil_la_SOURCES = \
|
||||
error.h \
|
||||
findfile.c \
|
||||
handlers.c \
|
||||
hashtable.c \
|
||||
menuparser.c \
|
||||
menuparser.h \
|
||||
menuparser_macros.c \
|
||||
|
||||
@@ -337,7 +337,8 @@ void WHandleEvents(void);
|
||||
/* ---[ WINGs/hashtable.c ]----------------------------------------------- */
|
||||
|
||||
|
||||
WMHashTable* WMCreateHashTable(const WMHashTableCallbacks callbacks);
|
||||
WMHashTable* WMCreateIdentityHashTable();
|
||||
WMHashTable* WMCreateStringHashTable();
|
||||
|
||||
void WMFreeHashTable(WMHashTable *table);
|
||||
|
||||
|
||||
@@ -1,401 +0,0 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "WUtil.h"
|
||||
|
||||
#define INITIAL_CAPACITY 23
|
||||
|
||||
|
||||
typedef struct HashItem {
|
||||
const void *key;
|
||||
const void *data;
|
||||
|
||||
struct HashItem *next; /* collided item list */
|
||||
} HashItem;
|
||||
|
||||
typedef struct W_HashTable {
|
||||
WMHashTableCallbacks callbacks;
|
||||
|
||||
unsigned itemCount;
|
||||
unsigned size; /* table size */
|
||||
|
||||
HashItem **table;
|
||||
} HashTable;
|
||||
|
||||
#define HASH(table, key) (((table)->callbacks.hash ? \
|
||||
(*(table)->callbacks.hash)(key) : hashPtr(key)) % (table)->size)
|
||||
|
||||
static inline unsigned hashString(const void *param)
|
||||
{
|
||||
const char *key = param;
|
||||
unsigned ret = 0;
|
||||
unsigned ctr = 0;
|
||||
|
||||
while (*key) {
|
||||
ret ^= *key++ << ctr;
|
||||
ctr = (ctr + 1) % sizeof(char *);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline unsigned hashPtr(const void *key)
|
||||
{
|
||||
return ((size_t) key / sizeof(char *));
|
||||
}
|
||||
|
||||
static void rellocateItem(WMHashTable * table, HashItem * item)
|
||||
{
|
||||
unsigned h;
|
||||
|
||||
h = HASH(table, item->key);
|
||||
|
||||
item->next = table->table[h];
|
||||
table->table[h] = item;
|
||||
}
|
||||
|
||||
static void rebuildTable(WMHashTable * table)
|
||||
{
|
||||
HashItem *next;
|
||||
HashItem **oldArray;
|
||||
int i;
|
||||
int oldSize;
|
||||
int newSize;
|
||||
|
||||
oldArray = table->table;
|
||||
oldSize = table->size;
|
||||
|
||||
newSize = table->size * 2;
|
||||
|
||||
table->table = wmalloc(sizeof(char *) * newSize);
|
||||
table->size = newSize;
|
||||
|
||||
for (i = 0; i < oldSize; i++) {
|
||||
while (oldArray[i] != NULL) {
|
||||
next = oldArray[i]->next;
|
||||
rellocateItem(table, oldArray[i]);
|
||||
oldArray[i] = next;
|
||||
}
|
||||
}
|
||||
wfree(oldArray);
|
||||
}
|
||||
|
||||
WMHashTable *WMCreateHashTable(const WMHashTableCallbacks callbacks)
|
||||
{
|
||||
HashTable *table;
|
||||
|
||||
table = wmalloc(sizeof(HashTable));
|
||||
|
||||
table->callbacks = callbacks;
|
||||
|
||||
table->size = INITIAL_CAPACITY;
|
||||
|
||||
table->table = wmalloc(sizeof(HashItem *) * table->size);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
void WMResetHashTable(WMHashTable * table)
|
||||
{
|
||||
HashItem *item, *tmp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < table->size; i++) {
|
||||
item = table->table[i];
|
||||
while (item) {
|
||||
tmp = item->next;
|
||||
wfree(item);
|
||||
item = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
table->itemCount = 0;
|
||||
|
||||
if (table->size > INITIAL_CAPACITY) {
|
||||
wfree(table->table);
|
||||
table->size = INITIAL_CAPACITY;
|
||||
table->table = wmalloc(sizeof(HashItem *) * table->size);
|
||||
} else {
|
||||
memset(table->table, 0, sizeof(HashItem *) * table->size);
|
||||
}
|
||||
}
|
||||
|
||||
void WMFreeHashTable(WMHashTable * table)
|
||||
{
|
||||
HashItem *item, *tmp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < table->size; i++) {
|
||||
item = table->table[i];
|
||||
while (item) {
|
||||
tmp = item->next;
|
||||
wfree(item);
|
||||
item = tmp;
|
||||
}
|
||||
}
|
||||
wfree(table->table);
|
||||
wfree(table);
|
||||
}
|
||||
|
||||
unsigned WMCountHashTable(WMHashTable * table)
|
||||
{
|
||||
return table->itemCount;
|
||||
}
|
||||
|
||||
static HashItem *hashGetItem(WMHashTable *table, const void *key)
|
||||
{
|
||||
unsigned h;
|
||||
HashItem *item;
|
||||
|
||||
h = HASH(table, key);
|
||||
item = table->table[h];
|
||||
|
||||
if (table->callbacks.keyIsEqual) {
|
||||
while (item) {
|
||||
if ((*table->callbacks.keyIsEqual) (key, item->key)) {
|
||||
break;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
} else {
|
||||
while (item) {
|
||||
if (key == item->key) {
|
||||
break;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
void *WMHashGet(WMHashTable * table, const void *key)
|
||||
{
|
||||
HashItem *item;
|
||||
|
||||
item = hashGetItem(table, key);
|
||||
if (!item)
|
||||
return NULL;
|
||||
return (void *)item->data;
|
||||
}
|
||||
|
||||
Bool WMHashGetItemAndKey(WMHashTable * table, const void *key, void **retItem, void **retKey)
|
||||
{
|
||||
HashItem *item;
|
||||
|
||||
item = hashGetItem(table, key);
|
||||
if (!item)
|
||||
return False;
|
||||
|
||||
if (retKey)
|
||||
*retKey = (void *)item->key;
|
||||
if (retItem)
|
||||
*retItem = (void *)item->data;
|
||||
return True;
|
||||
}
|
||||
|
||||
void *WMHashInsert(WMHashTable * table, const void *key, const void *data)
|
||||
{
|
||||
unsigned h;
|
||||
HashItem *item;
|
||||
int replacing = 0;
|
||||
|
||||
h = HASH(table, key);
|
||||
/* look for the entry */
|
||||
item = table->table[h];
|
||||
if (table->callbacks.keyIsEqual) {
|
||||
while (item) {
|
||||
if ((*table->callbacks.keyIsEqual) (key, item->key)) {
|
||||
replacing = 1;
|
||||
break;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
} else {
|
||||
while (item) {
|
||||
if (key == item->key) {
|
||||
replacing = 1;
|
||||
break;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (replacing) {
|
||||
const void *old;
|
||||
|
||||
old = item->data;
|
||||
item->data = data;
|
||||
item->key = key;
|
||||
|
||||
return (void *)old;
|
||||
} else {
|
||||
HashItem *nitem;
|
||||
|
||||
nitem = wmalloc(sizeof(HashItem));
|
||||
nitem->key = key;
|
||||
nitem->data = data;
|
||||
nitem->next = table->table[h];
|
||||
table->table[h] = nitem;
|
||||
|
||||
table->itemCount++;
|
||||
}
|
||||
|
||||
/* OPTIMIZE: put this in an idle handler. */
|
||||
if (table->itemCount > table->size) {
|
||||
#ifdef DEBUG0
|
||||
printf("rebuilding hash table...\n");
|
||||
#endif
|
||||
rebuildTable(table);
|
||||
#ifdef DEBUG0
|
||||
printf("finished rebuild.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HashItem *deleteFromList(HashTable * table, HashItem * item, const void *key)
|
||||
{
|
||||
HashItem *next;
|
||||
|
||||
if (item == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((table->callbacks.keyIsEqual && (*table->callbacks.keyIsEqual) (key, item->key))
|
||||
|| (!table->callbacks.keyIsEqual && key == item->key)) {
|
||||
|
||||
next = item->next;
|
||||
wfree(item);
|
||||
|
||||
table->itemCount--;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
item->next = deleteFromList(table, item->next, key);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void WMHashRemove(WMHashTable * table, const void *key)
|
||||
{
|
||||
unsigned h;
|
||||
|
||||
h = HASH(table, key);
|
||||
|
||||
table->table[h] = deleteFromList(table, table->table[h], key);
|
||||
}
|
||||
|
||||
WMHashEnumerator WMEnumerateHashTable(WMHashTable * table)
|
||||
{
|
||||
WMHashEnumerator enumerator;
|
||||
|
||||
enumerator.table = table;
|
||||
enumerator.index = 0;
|
||||
enumerator.nextItem = table->table[0];
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
void *WMNextHashEnumeratorItem(WMHashEnumerator * enumerator)
|
||||
{
|
||||
const void *data = NULL;
|
||||
|
||||
/* this assumes the table doesn't change between
|
||||
* WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
|
||||
|
||||
if (enumerator->nextItem == NULL) {
|
||||
HashTable *table = enumerator->table;
|
||||
while (++enumerator->index < table->size) {
|
||||
if (table->table[enumerator->index] != NULL) {
|
||||
enumerator->nextItem = table->table[enumerator->index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enumerator->nextItem) {
|
||||
data = ((HashItem *) enumerator->nextItem)->data;
|
||||
enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
|
||||
}
|
||||
|
||||
return (void *)data;
|
||||
}
|
||||
|
||||
void *WMNextHashEnumeratorKey(WMHashEnumerator * enumerator)
|
||||
{
|
||||
const void *key = NULL;
|
||||
|
||||
/* this assumes the table doesn't change between
|
||||
* WMEnumerateHashTable() and WMNextHashEnumeratorKey() calls */
|
||||
|
||||
if (enumerator->nextItem == NULL) {
|
||||
HashTable *table = enumerator->table;
|
||||
while (++enumerator->index < table->size) {
|
||||
if (table->table[enumerator->index] != NULL) {
|
||||
enumerator->nextItem = table->table[enumerator->index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enumerator->nextItem) {
|
||||
key = ((HashItem *) enumerator->nextItem)->key;
|
||||
enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
|
||||
}
|
||||
|
||||
return (void *)key;
|
||||
}
|
||||
|
||||
Bool WMNextHashEnumeratorItemAndKey(WMHashEnumerator * enumerator, void **item, void **key)
|
||||
{
|
||||
/* this assumes the table doesn't change between
|
||||
* WMEnumerateHashTable() and WMNextHashEnumeratorItemAndKey() calls */
|
||||
|
||||
if (enumerator->nextItem == NULL) {
|
||||
HashTable *table = enumerator->table;
|
||||
while (++enumerator->index < table->size) {
|
||||
if (table->table[enumerator->index] != NULL) {
|
||||
enumerator->nextItem = table->table[enumerator->index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enumerator->nextItem) {
|
||||
if (item)
|
||||
*item = (void *)((HashItem *) enumerator->nextItem)->data;
|
||||
if (key)
|
||||
*key = (void *)((HashItem *) enumerator->nextItem)->key;
|
||||
enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
static Bool compareStrings(const void *param1, const void *param2)
|
||||
{
|
||||
const char *key1 = param1;
|
||||
const char *key2 = param2;
|
||||
|
||||
return strcmp(key1, key2) == 0;
|
||||
}
|
||||
|
||||
typedef void *(*retainFunc) (const void *);
|
||||
typedef void (*releaseFunc) (const void *);
|
||||
|
||||
const WMHashTableCallbacks WMIntHashCallbacks = {
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
const WMHashTableCallbacks WMStringPointerHashCallbacks = {
|
||||
hashString,
|
||||
compareStrings,
|
||||
};
|
||||
@@ -88,10 +88,10 @@ static NotificationCenter *notificationCenter = NULL;
|
||||
void W_InitNotificationCenter(void)
|
||||
{
|
||||
notificationCenter = wmalloc(sizeof(NotificationCenter));
|
||||
notificationCenter->nameTable = WMCreateHashTable(WMStringPointerHashCallbacks);
|
||||
notificationCenter->objectTable = WMCreateHashTable(WMIntHashCallbacks);
|
||||
notificationCenter->nameTable = WMCreateStringHashTable();
|
||||
notificationCenter->objectTable = WMCreateIdentityHashTable();
|
||||
notificationCenter->nilList = NULL;
|
||||
notificationCenter->observerTable = WMCreateHashTable(WMIntHashCallbacks);
|
||||
notificationCenter->observerTable = WMCreateIdentityHashTable();
|
||||
}
|
||||
|
||||
void W_ReleaseNotificationCenter(void)
|
||||
|
||||
@@ -65,7 +65,7 @@ struct W_Balloon *W_CreateBalloon(WMScreen * scr)
|
||||
W_ResizeView(bPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
|
||||
bPtr->flags.alignment = DEFAULT_ALIGNMENT;
|
||||
|
||||
bPtr->table = WMCreateHashTable(WMIntHashCallbacks);
|
||||
bPtr->table = WMCreateIdentityHashTable();
|
||||
|
||||
bPtr->delay = DEFAULT_DELAY;
|
||||
|
||||
|
||||
@@ -535,7 +535,7 @@ static void listFamilies(WMScreen * scr, WMFontPanel * panel)
|
||||
if (pat)
|
||||
FcPatternDestroy(pat);
|
||||
|
||||
families = WMCreateHashTable(WMStringPointerHashCallbacks);
|
||||
families = WMCreateStringHashTable();
|
||||
|
||||
if (fs) {
|
||||
for (i = 0; i < fs->nfont; i++) {
|
||||
|
||||
@@ -630,7 +630,7 @@ WMScreen *WMCreateScreenWithRContext(Display * display, int screen, RContext * c
|
||||
|
||||
scrPtr->rootWin = RootWindow(display, screen);
|
||||
|
||||
scrPtr->fontCache = WMCreateHashTable(WMStringPointerHashCallbacks);
|
||||
scrPtr->fontCache = WMCreateStringHashTable();
|
||||
|
||||
scrPtr->xftdraw = XftDrawCreate(scrPtr->display, W_DRAWABLE(scrPtr), scrPtr->visual, scrPtr->colormap);
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ WPrefs_DEPENDENCIES = $(top_builddir)/WINGs/libWINGs.la
|
||||
|
||||
WPrefs_LDADD = \
|
||||
$(top_builddir)/wutil-rs/target/debug/libwutil_rs.a\
|
||||
$(top_builddir)/wings-rs/target/debug/libwings_rs.la\
|
||||
$(top_builddir)/WINGs/libWINGs.la\
|
||||
$(top_builddir)/WINGs/libWUtil.la\
|
||||
$(top_builddir)/wrlib/libwraster.la \
|
||||
|
||||
@@ -134,7 +134,7 @@ else
|
||||
nodist_wmaker_SOURCES = misc.hack_nf.c \
|
||||
xmodifier.hack_nf.c
|
||||
|
||||
CLEANFILES = $(nodist_wmaker_SOURCES) ../wmaker-rs/target
|
||||
CLEANFILES = $(nodist_wmaker_SOURCES)
|
||||
|
||||
misc.hack_nf.c: misc.c $(top_srcdir)/script/nested-func-to-macro.sh
|
||||
$(AM_V_GEN)$(top_srcdir)/script/nested-func-to-macro.sh \
|
||||
@@ -160,6 +160,7 @@ wmaker_LDADD = \
|
||||
$(top_builddir)/WINGs/libWINGs.la\
|
||||
$(top_builddir)/WINGs/libWUtil.la\
|
||||
$(top_builddir)/wrlib/libwraster.la\
|
||||
$(top_builddir)/wutil-rs/target/debug/libwutil_rs.a\
|
||||
$(top_builddir)/wmaker-rs/target/debug/libwmaker_rs.a\
|
||||
@XLFLAGS@ \
|
||||
@LIBXRANDR@ \
|
||||
|
||||
@@ -11,5 +11,8 @@ cc = "1.0"
|
||||
|
||||
[dependencies]
|
||||
atomic-write-file = "0.3"
|
||||
hashbrown = "0.16.0"
|
||||
libc = "0.2.175"
|
||||
nom = "8.0"
|
||||
nom-language = "0.1"
|
||||
x11 = "2.21.0"
|
||||
|
||||
@@ -2,9 +2,11 @@ AUTOMAKE_OPTIONS =
|
||||
|
||||
RUST_SOURCES = \
|
||||
src/array.rs \
|
||||
src/data.rs \
|
||||
src/defines.c \
|
||||
src/defines.rs \
|
||||
src/find_file.rs \
|
||||
src/hash_table.rs \
|
||||
src/lib.rs \
|
||||
src/memory.rs \
|
||||
src/prop_list.rs
|
||||
|
||||
328
wutil-rs/src/hash_table.rs
Normal file
328
wutil-rs/src/hash_table.rs
Normal file
@@ -0,0 +1,328 @@
|
||||
use hashbrown::hash_map::{self, HashMap};
|
||||
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
ffi::{CStr, c_void},
|
||||
hash::{Hash, Hasher},
|
||||
mem,
|
||||
};
|
||||
|
||||
pub enum HashTable {
|
||||
PointerKeyed(HashMap<VoidPointer, VoidPointer>),
|
||||
StringKeyed(HashMap<StringPointer, VoidPointer>),
|
||||
}
|
||||
|
||||
impl HashTable {
|
||||
pub fn new_pointer_keyed() -> Self {
|
||||
HashTable::PointerKeyed(HashMap::new())
|
||||
}
|
||||
|
||||
pub fn new_string_keyed() -> Self {
|
||||
HashTable::StringKeyed(HashMap::new())
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
match self {
|
||||
HashTable::PointerKeyed(m) => m.clear(),
|
||||
HashTable::StringKeyed(m) => m.clear(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
HashTable::PointerKeyed(m) => m.len(),
|
||||
HashTable::StringKeyed(m) => m.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn get(&self, key: *const i8) -> Option<*mut i8> {
|
||||
match self {
|
||||
HashTable::PointerKeyed(m) => {
|
||||
let key = key.cast_mut();
|
||||
m.get(&key).map(|x| x.0)
|
||||
}
|
||||
HashTable::StringKeyed(m) => {
|
||||
let key = StringPointer(key.cast_mut());
|
||||
let v = m.get(&key).map(|x| x.0);
|
||||
mem::forget(key);
|
||||
v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn insert(&mut self, key: *mut i8, data: VoidPointer) -> Option<VoidPointer> {
|
||||
match self {
|
||||
HashTable::PointerKeyed(m) => m.insert(VoidPointer(key), data),
|
||||
HashTable::StringKeyed(m) => m.insert(StringPointer(key), data),
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn remove(&mut self, key: *const i8) {
|
||||
match self {
|
||||
HashTable::PointerKeyed(m) => {
|
||||
let key = key.cast_mut();
|
||||
m.remove(&key);
|
||||
}
|
||||
HashTable::StringKeyed(m) => {
|
||||
let key = StringPointer(key.cast_mut());
|
||||
m.remove(&key);
|
||||
mem::forget(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct VoidPointer(*mut i8);
|
||||
|
||||
impl Drop for VoidPointer {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libc::free(self.0.cast::<c_void>()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<*mut i8> for VoidPointer {
|
||||
fn borrow(&self) -> &*mut i8 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct StringPointer(*mut i8);
|
||||
|
||||
impl PartialEq for StringPointer {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.0.is_null(), other.0.is_null()) {
|
||||
(true, true) => true,
|
||||
(true, false) => false,
|
||||
(false, true) => false,
|
||||
(false, false) => unsafe { CStr::from_ptr(self.0) == CStr::from_ptr(other.0) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for StringPointer {}
|
||||
|
||||
impl Hash for StringPointer {
|
||||
fn hash<H: Hasher>(&self, h: &mut H) {
|
||||
if self.0.is_null() {
|
||||
h.write_usize(0)
|
||||
} else {
|
||||
unsafe { CStr::from_ptr(self.0).hash(h) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for StringPointer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
libc::free(self.0.cast::<c_void>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Enumerator<'a> {
|
||||
PointerKeyed(hash_map::IterMut<'a, VoidPointer, VoidPointer>),
|
||||
StringKeyed(hash_map::IterMut<'a, StringPointer, VoidPointer>),
|
||||
}
|
||||
|
||||
pub mod ffi {
|
||||
use std::{
|
||||
ffi::{c_int, c_uint, c_void},
|
||||
mem, ptr,
|
||||
};
|
||||
|
||||
use super::{Enumerator, HashTable, StringPointer, VoidPointer};
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn WMCreateIdentityHashTable() -> *mut HashTable {
|
||||
Box::leak(Box::new(HashTable::new_pointer_keyed()))
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn WMCreateStringHashTable() -> *mut HashTable {
|
||||
Box::leak(Box::new(HashTable::new_string_keyed()))
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn WMFreeHashTable(table: *mut HashTable) {
|
||||
if !table.is_null() {
|
||||
let _ = unsafe { Box::from_raw(table) };
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn WMResetHashTable(table: *mut HashTable) {
|
||||
if !table.is_null() {
|
||||
unsafe {
|
||||
(*table).clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn WMCountHashTable(table: *mut HashTable) -> c_uint {
|
||||
if table.is_null() {
|
||||
0
|
||||
} else {
|
||||
(unsafe { (*table).len() }) as c_uint
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn WMHashGet(table: *mut HashTable, key: *const c_void) -> *mut c_void {
|
||||
if table.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let key = key.cast::<i8>();
|
||||
(unsafe { (*table).get(key) })
|
||||
.map(|v| v.cast::<c_void>())
|
||||
.unwrap_or(ptr::null_mut())
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMHashGetItemAndKey(
|
||||
table: *mut HashTable,
|
||||
key: *const c_void,
|
||||
value_dest: *mut *mut c_void,
|
||||
key_dest: *mut *const c_void,
|
||||
) -> c_int {
|
||||
if table.is_null() {
|
||||
return 0;
|
||||
}
|
||||
let table = unsafe { &mut *table };
|
||||
match table {
|
||||
HashTable::PointerKeyed(m) => {
|
||||
let key = VoidPointer(key.cast::<i8>().cast_mut());
|
||||
let result = match m.get_key_value_mut(&key) {
|
||||
Some((k, v)) => {
|
||||
unsafe {
|
||||
*key_dest = k.0.cast::<c_void>();
|
||||
*value_dest = v.0.cast::<c_void>();
|
||||
}
|
||||
1
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
mem::forget(key);
|
||||
result
|
||||
}
|
||||
HashTable::StringKeyed(m) => {
|
||||
let key = StringPointer(key.cast::<i8>().cast_mut());
|
||||
let result = match m.get_key_value_mut(&key) {
|
||||
Some((k, v)) => {
|
||||
unsafe {
|
||||
*key_dest = k.0.cast::<c_void>();
|
||||
*value_dest = v.0.cast::<c_void>();
|
||||
}
|
||||
1
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
mem::forget(key);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn WMHashInsert(
|
||||
table: *mut HashTable,
|
||||
key: *mut c_void,
|
||||
data: *mut c_void,
|
||||
) -> *mut c_void {
|
||||
if table.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
match unsafe { (*table).insert(key.cast::<i8>(), VoidPointer(data.cast::<i8>())) } {
|
||||
Some(v) => {
|
||||
let raw = v.0;
|
||||
mem::forget(v);
|
||||
raw.cast::<c_void>()
|
||||
}
|
||||
None => ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn WMHashRemove(table: *mut HashTable, key: *mut c_void) {
|
||||
if table.is_null() {
|
||||
return;
|
||||
}
|
||||
unsafe {
|
||||
(*table).remove(key.cast::<i8>());
|
||||
}
|
||||
}
|
||||
|
||||
/// Important note: this may leak memory if you don't pass the enumerator
|
||||
/// back to [`WMFreeHashEnumerator`]. This is a breaking change from the
|
||||
/// original C implementation, which did not require any resource cleanup.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMEnumerateHashTable(
|
||||
table: *mut HashTable,
|
||||
) -> *mut Enumerator<'static> {
|
||||
if table.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let table = unsafe { &mut *table };
|
||||
match table {
|
||||
HashTable::PointerKeyed(m) => {
|
||||
Box::leak(Box::new(Enumerator::PointerKeyed(m.iter_mut())))
|
||||
}
|
||||
HashTable::StringKeyed(m) => Box::leak(Box::new(Enumerator::StringKeyed(m.iter_mut()))),
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMFreeHashEnumerator(e: *mut Enumerator<'static>) {
|
||||
if !e.is_null() {
|
||||
let _ = unsafe { Box::from_raw(e) };
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMNextHashEnumeratorItem(e: *mut Enumerator<'static>) -> *mut c_void {
|
||||
if e.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let e = unsafe { &mut *e };
|
||||
match e {
|
||||
Enumerator::PointerKeyed(i) => match i.next() {
|
||||
Some((_, v)) => v.0.cast::<c_void>(),
|
||||
None => ptr::null_mut(),
|
||||
},
|
||||
Enumerator::StringKeyed(i) => match i.next() {
|
||||
Some((_, v)) => v.0.cast::<c_void>(),
|
||||
None => ptr::null_mut(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMNextHashEnumeratorKey(e: *mut Enumerator<'static>) -> *mut c_void {
|
||||
if e.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let e = unsafe { &mut *e };
|
||||
match e {
|
||||
Enumerator::PointerKeyed(i) => match i.next() {
|
||||
Some((k, _)) => k.0.cast::<c_void>(),
|
||||
None => ptr::null_mut(),
|
||||
},
|
||||
Enumerator::StringKeyed(i) => match i.next() {
|
||||
Some((k, _)) => k.0.cast::<c_void>(),
|
||||
None => ptr::null_mut(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,6 @@ pub mod array;
|
||||
pub mod data;
|
||||
pub mod defines;
|
||||
pub mod find_file;
|
||||
pub mod hash_table;
|
||||
pub mod memory;
|
||||
pub mod prop_list;
|
||||
|
||||
Reference in New Issue
Block a user