From f2e9123db6f52e0902e1468c59b5ec17eacb77a7 Mon Sep 17 00:00:00 2001 From: Stu Black Date: Sat, 4 Oct 2025 12:31:54 -0400 Subject: [PATCH] Port WINGs data.c (WMData) to Rust. This is not tested super well, but I hope we can be rid of it soon enough. (Once we have WMPropList migrated, WMData and other WINGs data structures should be easier to prune.) --- WINGs/Makefile.am | 1 - WINGs/WINGs/WUtil.h | 18 --- WINGs/data.c | 255 ------------------------------------------- wutil-rs/src/data.rs | 196 +++++++++++++++++++++++++++++++++ wutil-rs/src/lib.rs | 1 + 5 files changed, 197 insertions(+), 274 deletions(-) delete mode 100644 WINGs/data.c create mode 100644 wutil-rs/src/data.rs diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index 308f140c..88fcad31 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -65,7 +65,6 @@ libWINGs_la_SOURCES = \ libWUtil_la_SOURCES = \ bagtree.c \ - data.c \ error.c \ error.h \ findfile.c \ diff --git a/WINGs/WINGs/WUtil.h b/WINGs/WINGs/WUtil.h index 1277f985..a4390640 100644 --- a/WINGs/WINGs/WUtil.h +++ b/WINGs/WINGs/WUtil.h @@ -598,24 +598,10 @@ WMData* WMRetainData(WMData *aData); void WMReleaseData(WMData *aData); -/* Adjusting capacity */ - -void WMSetDataCapacity(WMData *aData, unsigned capacity); - -void WMSetDataLength(WMData *aData, unsigned length); - -void WMIncreaseDataLengthBy(WMData *aData, unsigned extraLength); - /* Accessing data */ const void* WMDataBytes(WMData *aData); -void WMGetDataBytes(WMData *aData, void *buffer); - -void WMGetDataBytesWithLength(WMData *aData, void *buffer, unsigned length); - -void WMGetDataBytesWithRange(WMData *aData, void *buffer, WMRange aRange); - /* Testing data */ Bool WMIsDataEqualToData(WMData *aData, WMData *anotherData); @@ -630,10 +616,6 @@ void WMAppendData(WMData *aData, WMData *anotherData); /* Modifying data */ -void WMReplaceDataBytesInRange(WMData *aData, WMRange aRange, const void *bytes); - -void WMResetDataBytesInRange(WMData *aData, WMRange aRange); - void WMSetData(WMData *aData, WMData *anotherData); diff --git a/WINGs/data.c b/WINGs/data.c deleted file mode 100644 index c775451b..00000000 --- a/WINGs/data.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * WINGs WMData function library - * - * Copyright (c) 1999-2003 Dan Pascu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include -#include "WUtil.h" - -typedef struct W_Data { - unsigned length; /* How many bytes we have */ - unsigned capacity; /* How many bytes it can hold */ - unsigned growth; /* How much to grow */ - void *bytes; /* Actual data */ - unsigned retainCount; - int format; /* 0, 8, 16 or 32 */ -} W_Data; - -/* Creating and destroying data objects */ - -WMData *WMCreateDataWithCapacity(unsigned capacity) -{ - WMData *aData; - - aData = (WMData *) wmalloc(sizeof(WMData)); - - if (capacity > 0) - aData->bytes = wmalloc(capacity); - else - aData->bytes = NULL; - - aData->capacity = capacity; - aData->growth = capacity / 2 > 0 ? capacity / 2 : 1; - aData->length = 0; - aData->retainCount = 1; - aData->format = 0; - - return aData; -} - -WMData *WMCreateDataWithLength(unsigned length) -{ - WMData *aData; - - aData = WMCreateDataWithCapacity(length); - if (length > 0) { - aData->length = length; - } - - return aData; -} - -WMData *WMCreateDataWithBytes(const void *bytes, unsigned length) -{ - WMData *aData; - - aData = WMCreateDataWithCapacity(length); - aData->length = length; - memcpy(aData->bytes, bytes, length); - - return aData; -} - -WMData *WMCreateDataWithData(WMData * aData) -{ - WMData *newData; - - if (aData->length > 0) { - newData = WMCreateDataWithBytes(aData->bytes, aData->length); - } else { - newData = WMCreateDataWithCapacity(0); - } - newData->format = aData->format; - - return newData; -} - -WMData *WMRetainData(WMData * aData) -{ - aData->retainCount++; - return aData; -} - -void WMReleaseData(WMData * aData) -{ - aData->retainCount--; - if (aData->retainCount > 0) - return; - if (aData->bytes != NULL) { - wfree(aData->bytes); - } - wfree(aData); -} - -/* Adjusting capacity */ - -void WMSetDataCapacity(WMData * aData, unsigned capacity) -{ - if (aData->capacity != capacity) { - aData->bytes = wrealloc(aData->bytes, capacity); - aData->capacity = capacity; - aData->growth = capacity / 2 > 0 ? capacity / 2 : 1; - } - if (aData->length > capacity) { - aData->length = capacity; - } -} - -void WMSetDataLength(WMData * aData, unsigned length) -{ - if (length > aData->capacity) { - WMSetDataCapacity(aData, length); - } - if (length > aData->length) { - memset((unsigned char *)aData->bytes + aData->length, 0, length - aData->length); - } - aData->length = length; -} - -void WMSetDataFormat(WMData * aData, unsigned format) -{ - aData->format = format; -} - -void WMIncreaseDataLengthBy(WMData * aData, unsigned extraLength) -{ - WMSetDataLength(aData, aData->length + extraLength); -} - -/* Accessing data */ - -const void *WMDataBytes(WMData * aData) -{ - return aData->bytes; -} - -void WMGetDataBytes(WMData * aData, void *buffer) -{ - wassertr(aData->length > 0); - - memcpy(buffer, aData->bytes, aData->length); -} - -unsigned WMGetDataFormat(WMData * aData) -{ - return aData->format; -} - -void WMGetDataBytesWithLength(WMData * aData, void *buffer, unsigned length) -{ - wassertr(aData->length > 0); - wassertr(length <= aData->length); - - memcpy(buffer, aData->bytes, length); -} - -void WMGetDataBytesWithRange(WMData * aData, void *buffer, WMRange aRange) -{ - wassertr(aRange.position < aData->length); - wassertr(aRange.count <= aData->length - aRange.position); - - memcpy(buffer, (unsigned char *)aData->bytes + aRange.position, aRange.count); -} - -/* Testing data */ - -Bool WMIsDataEqualToData(WMData * aData, WMData * anotherData) -{ - if (aData->length != anotherData->length) - return False; - else if (!aData->bytes && !anotherData->bytes) /* both are empty */ - return True; - else if (!aData->bytes || !anotherData->bytes) /* one of them is empty */ - return False; - return (memcmp(aData->bytes, anotherData->bytes, aData->length) == 0); -} - -unsigned WMGetDataLength(WMData * aData) -{ - return aData->length; -} - -/* Adding data */ -void WMAppendDataBytes(WMData * aData, const void *bytes, unsigned length) -{ - unsigned oldLength = aData->length; - unsigned newLength = oldLength + length; - - if (newLength > aData->capacity) { - unsigned nextCapacity = aData->capacity + aData->growth; - unsigned nextGrowth = aData->capacity ? aData->capacity : 1; - - while (nextCapacity < newLength) { - unsigned tmp = nextCapacity + nextGrowth; - - nextGrowth = nextCapacity; - nextCapacity = tmp; - } - WMSetDataCapacity(aData, nextCapacity); - aData->growth = nextGrowth; - } - memcpy((unsigned char *)aData->bytes + oldLength, bytes, length); - aData->length = newLength; -} - -void WMAppendData(WMData * aData, WMData * anotherData) -{ - if (anotherData->length > 0) - WMAppendDataBytes(aData, anotherData->bytes, anotherData->length); -} - -/* Modifying data */ - -void WMReplaceDataBytesInRange(WMData * aData, WMRange aRange, const void *bytes) -{ - wassertr(aRange.position < aData->length); - wassertr(aRange.count <= aData->length - aRange.position); - - memcpy((unsigned char *)aData->bytes + aRange.position, bytes, aRange.count); -} - -void WMResetDataBytesInRange(WMData * aData, WMRange aRange) -{ - wassertr(aRange.position < aData->length); - wassertr(aRange.count <= aData->length - aRange.position); - - memset((unsigned char *)aData->bytes + aRange.position, 0, aRange.count); -} - -void WMSetData(WMData * aData, WMData * anotherData) -{ - unsigned length = anotherData->length; - - WMSetDataCapacity(aData, length); - if (length > 0) - memcpy(aData->bytes, anotherData->bytes, length); - aData->length = length; -} - -/* Storing data */ diff --git a/wutil-rs/src/data.rs b/wutil-rs/src/data.rs new file mode 100644 index 00000000..aff4788e --- /dev/null +++ b/wutil-rs/src/data.rs @@ -0,0 +1,196 @@ +//! Self-owning shared data segment. + +use std::{cell::RefCell, rc::Rc}; + +#[derive(Clone, Copy, Debug)] +pub enum Format { + Z = 0, + E = 8, + S = 16, + T = 32, +} + +/// Reference-counted, self-owned, dynamically sized chunk of bytes. +/// +/// In the original WINGs, this type either owned or borrowed a data buffer and +/// had some associated metadata. In Rust, this is little more than a thin +/// wrapper around an `Rc>>`. It is mostly used by proplists, +/// and it should be done away with once its dependents have been ported to +/// Rust. +pub struct Data(Rc>); + +struct Inner { + bytes: Vec, + format: Format, +} + +pub mod ffi { + use super::{Data, Format, Inner}; + + use std::{ + cell::RefCell, + ffi::{c_int, c_uint, c_void}, + ptr, + rc::Rc, + }; + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMCreateDataWithCapacity(capacity: c_uint) -> *mut Data { + Box::leak(Box::new(Data(Rc::new(RefCell::new(Inner { + bytes: Vec::with_capacity(capacity as usize), + format: Format::Z, + }))))) + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMCreateDataWithLength(length: c_uint) -> *mut Data { + Box::leak(Box::new(Data(Rc::new(RefCell::new(Inner { + bytes: vec![0; length as usize], + format: Format::Z, + }))))) + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMCreateDataWithBytes( + bytes: *const c_void, + length: c_uint, + ) -> *mut Data { + let bytes = unsafe { &*ptr::slice_from_raw_parts(bytes.cast::(), length as usize) }; + let bytes = Vec::from(bytes); + Box::leak(Box::new(Data(Rc::new(RefCell::new(Inner { + bytes, + format: Format::Z, + }))))) + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMCreateDataWithData(data: *mut Data) -> *mut Data { + if data.is_null() { + return ptr::null_mut(); + } + let data = unsafe { &*data }; + Box::leak(Box::new(Data(Rc::new(RefCell::new(Inner { + bytes: data.0.borrow().bytes.clone(), + format: data.0.borrow().format, + }))))) + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMRetainData(data: *mut Data) -> *mut Data { + if data.is_null() { + return ptr::null_mut(); + } + let data = unsafe { &*data }; + Box::leak(Box::new(Data(data.0.clone()))) + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMReleaseData(data: *mut Data) { + if data.is_null() { + return; + } + let _ = unsafe { ptr::read(data) }; + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMDataBytes(data: *mut Data) -> *const c_void { + if data.is_null() { + return ptr::null(); + } + + unsafe { (*data).0.borrow().bytes.as_ptr().cast::() } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMIsDataEqualToData(a: *mut Data, b: *mut Data) -> c_int { + if a.is_null() || b.is_null() { + return 0; + } + if ptr::eq(a, b) { + return 1; + } + let a = unsafe { &*a }; + let b = unsafe { &*b }; + (a.0.borrow().bytes == b.0.borrow().bytes) as c_int + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMGetDataLength(data: *mut Data) -> c_uint { + if data.is_null() { + return 0; + } + unsafe { (*data).0.borrow().bytes.len() as c_uint } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMAppendDataBytes( + data: *mut Data, + bytes: *const c_void, + length: c_uint, + ) { + if data.is_null() || bytes.is_null() || length == 0 { + return; + } + let data = unsafe { &mut *data }; + let bytes = unsafe { &*ptr::slice_from_raw_parts(bytes.cast::(), length as usize) }; + data.0.borrow_mut().bytes.extend_from_slice(bytes); + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMAppendData(data: *mut Data, ext: *mut Data) { + if data.is_null() || ext.is_null() { + return; + } + let data = unsafe { &mut *data }; + let ext = unsafe { &*ext }; + data.0 + .borrow_mut() + .bytes + .extend_from_slice(&ext.0.borrow().bytes); + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMSetData(data: *mut Data, other: *mut Data) { + if data.is_null() || other.is_null() { + return; + } + let data = unsafe { &mut *data }; + let other = unsafe { &*other }; + data.0 + .borrow_mut() + .bytes + .copy_from_slice(&other.0.borrow().bytes); + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMGetDataFormat(data: *mut Data) -> c_uint { + if data.is_null() { + return 0; + } + return unsafe { + match (*data).0.borrow().format { + Format::Z => 0, + Format::E => 8, + Format::S => 16, + Format::T => 32, + } + }; + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMSetDataFormat(data: *mut Data, format: c_uint) { + if data.is_null() { + return; + } + let format = match format { + 0 => Format::Z, + 8 => Format::E, + 16 => Format::S, + 32 => Format::T, + _ => return, + }; + unsafe { + (*data).0.borrow_mut().format = format; + } + } +} diff --git a/wutil-rs/src/lib.rs b/wutil-rs/src/lib.rs index 970d30a5..5caabff8 100644 --- a/wutil-rs/src/lib.rs +++ b/wutil-rs/src/lib.rs @@ -1,3 +1,4 @@ pub mod array; +pub mod data; pub mod find_file; pub mod memory;