From 2d3828fb2bbd33ce8f90c4a4394ceb54e36535ef Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sat, 12 Apr 2025 16:47:40 +0200 Subject: [PATCH 1/3] add fn to pass ip:port as values --- example/main.c | 2 +- include/servicepoint.h | 21 ++++++++++++++++++++- src/connection.rs | 37 +++++++++++++++++++++++++------------ 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/example/main.c b/example/main.c index 4e63dec..e3cfc8f 100644 --- a/example/main.c +++ b/example/main.c @@ -2,7 +2,7 @@ #include "servicepoint.h" int main(void) { - UdpConnection *connection = sp_connection_open("localhost:2342"); + UdpConnection *connection = sp_connection_open_ipv4(127,0,0,1,2342); if (connection == NULL) return 1; diff --git a/include/servicepoint.h b/include/servicepoint.h index dbce14d..7c0c819 100644 --- a/include/servicepoint.h +++ b/include/servicepoint.h @@ -979,13 +979,32 @@ void sp_connection_free(UdpConnection */*notnull*/ connection); * # Examples * * ```C - * CConnection connection = sp_connection_open("172.23.42.29:2342"); + * UdpConnection connection = sp_connection_open("172.23.42.29:2342"); * if (connection != NULL) * sp_connection_send_command(connection, sp_command_clear()); * ``` */ UdpConnection *sp_connection_open(char */*notnull*/ host); +/** + * Creates a new instance of [UdpConnection]. + * + * returns: NULL if connection fails, or connected instance + * + * # Examples + * + * ```C + * UdpConnection connection = sp_connection_open_ipv4(172, 23, 42, 29, 2342); + * if (connection != NULL) + * sp_connection_send_command(connection, sp_command_clear()); + * ``` + */ +UdpConnection *sp_connection_open_ipv4(uint8_t ip1, + uint8_t ip2, + uint8_t ip3, + uint8_t ip4, + uint16_t port); + /** * Sends a [TypedCommand] to the display using the [UdpConnection]. * diff --git a/src/connection.rs b/src/connection.rs index 5feb528..d6ffb83 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,5 +1,6 @@ use servicepoint::{Connection, Packet, TypedCommand, UdpConnection}; use std::ffi::{c_char, CStr}; +use std::net::{Ipv4Addr, SocketAddrV4}; use std::ptr::NonNull; /// Creates a new instance of [UdpConnection]. @@ -9,7 +10,7 @@ use std::ptr::NonNull; /// # Examples /// /// ```C -/// CConnection connection = sp_connection_open("172.23.42.29:2342"); +/// UdpConnection connection = sp_connection_open("172.23.42.29:2342"); /// if (connection != NULL) /// sp_connection_send_command(connection, sp_command_clear()); /// ``` @@ -28,17 +29,29 @@ pub unsafe extern "C" fn sp_connection_open( Box::into_raw(Box::new(connection)) } -//#[no_mangle] -//pub unsafe extern "C" fn sp_connection_open_ipv4( -// host: SocketAddrV4, -//) -> *mut UdpConnection { -// let connection = match servicepoint::UdpConnection::open(host) { -// Err(_) => return std::ptr::null_mut(), -// Ok(value) => value, -// }; -// -// Box::into_raw(Box::new(UdpConnection(connection))) -//} +/// Creates a new instance of [UdpConnection]. +/// +/// returns: NULL if connection fails, or connected instance +/// +/// # Examples +/// +/// ```C +/// UdpConnection connection = sp_connection_open_ipv4(172, 23, 42, 29, 2342); +/// if (connection != NULL) +/// sp_connection_send_command(connection, sp_command_clear()); +/// ``` +#[no_mangle] +pub unsafe extern "C" fn sp_connection_open_ipv4( + ip1: u8, ip2: u8, ip3: u8, ip4: u8, + port: u16, +) -> *mut UdpConnection { + let addr = SocketAddrV4::new(Ipv4Addr::from( [ip1, ip2, ip3, ip4]), port); + let connection = match UdpConnection::open(addr) { + Err(_) => return std::ptr::null_mut(), + Ok(value) => value, + }; + Box::into_raw(Box::new(connection)) +} // /// Creates a new instance of [SPUdpConnection] for testing that does not actually send anything. // /// From d6331ea9a7eb8c5b95e68e36b127872760c72fcf Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sat, 12 Apr 2025 17:38:19 +0200 Subject: [PATCH 2/3] rename/merge functions to match rust side more --- Cargo.lock | 2 +- example/Makefile | 12 +- example/main.c | 10 +- include/servicepoint.h | 276 +++++++++++++++++++---------------------- src/bitmap.rs | 2 +- src/command.rs | 117 ++--------------- src/connection.rs | 26 +--- 7 files changed, 165 insertions(+), 280 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c0b11c4..f87ecea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -408,7 +408,7 @@ dependencies = [ [[package]] name = "servicepoint" version = "0.13.2" -source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#971bee5065139f220022e8108cfaa9c263b8a8a0" +source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#531d4e6b4a368dc126cab9dc12b64d2ca8a81694" dependencies = [ "bitvec", "bzip2", diff --git a/example/Makefile b/example/Makefile index e7d858f..d3f346f 100644 --- a/example/Makefile +++ b/example/Makefile @@ -63,11 +63,19 @@ out/example_unstripped: dependencies main.c $(CCFLAGS) \ -o out/example_unstripped out/example: out/example_unstripped - strip -s -R .comment -R .gnu.version --strip-unneeded out/example_unstripped -o out/example -#strip -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag + strip -s --strip-unneeded \ + -R .comment -R .gnu.version -R .comment -R .note -R .note.gnu.build-id -R .note.ABI-tag \ + out/example_unstripped \ + -o out/example dependencies: FORCE mkdir -p include || true # generate servicepoint header and binary to link against ${CARGO} rustc $(CARGOFLAGS) -- $(RUSTFLAGS) + +analyze-size: out/example_unstripped + nm --print-size --size-sort --reverse-sort --radix=d --demangle out/example_unstripped \ + | awk '{size=$$2+0; print size "\t" $$4}' \ + | less + FORCE: ; diff --git a/example/main.c b/example/main.c index e3cfc8f..9c0ec9e 100644 --- a/example/main.c +++ b/example/main.c @@ -2,7 +2,7 @@ #include "servicepoint.h" int main(void) { - UdpConnection *connection = sp_connection_open_ipv4(127,0,0,1,2342); + UdpConnection *connection = sp_udp_open_ipv4(127, 0, 0, 1, 2342); if (connection == NULL) return 1; @@ -12,17 +12,17 @@ int main(void) { sp_bitmap_fill(pixels, true); - TypedCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, COMPRESSION_CODE_UNCOMPRESSED); + TypedCommand *command = sp_command_bitmap(0, 0, pixels, COMPRESSION_CODE_UNCOMPRESSED); if (command == NULL) return 1; Packet *packet = sp_packet_from_command(command); Header *header = sp_packet_get_header(packet); - printf("[%d, %d, %d, %d, %d]\n", header->command_code, header->a, header->b, header->c, header->d); + //printf("[%d, %d, %d, %d, %d]\n", header->command_code, header->a, header->b, header->c, header->d); - sp_connection_send_packet(connection, packet); + sp_udp_send_packet(connection, packet); - sp_connection_free(connection); + sp_udp_free(connection); return 0; } diff --git a/include/servicepoint.h b/include/servicepoint.h index 7c0c819..8f7ca75 100644 --- a/include/servicepoint.h +++ b/include/servicepoint.h @@ -66,6 +66,35 @@ */ #define TILE_WIDTH 56 +/** + * Binary operations for use with the [`BitVecCommand`] command. + */ +enum BinaryOperation +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + /** + * r := a + */ + BINARY_OPERATION_OVERWRITE, + /** + * r := a && b + */ + BINARY_OPERATION_AND, + /** + * r := a || b + */ + BINARY_OPERATION_OR, + /** + * r := (a || b) && (a != b) + */ + BINARY_OPERATION_XOR, +}; +#ifndef __cplusplus +typedef uint8_t BinaryOperation; +#endif // __cplusplus + /** * Specifies the kind of compression to use. Availability depends on features. * @@ -428,7 +457,7 @@ Bitmap *sp_bitmap_new(size_t width, size_t height); * * returns: [Bitmap] initialized to all pixels off. */ -Bitmap */*notnull*/ sp_bitmap_new_screen_sized(void); +Bitmap */*notnull*/ sp_bitmap_new_max_sized(void); /** * Sets the value of the specified position in the [Bitmap]. @@ -791,81 +820,36 @@ void sp_char_grid_set(CharGrid */*notnull*/ char_grid, */ size_t sp_char_grid_width(CharGrid */*notnull*/ char_grid); +/** + * Sets a window of pixels to the specified values. + * + * The passed [Bitmap] gets consumed. + * + * Returns: a new [servicepoint::BitmapCommand] instance. + */ +TypedCommand *sp_command_bitmap(size_t x, + size_t y, + Bitmap */*notnull*/ bitmap, + CompressionCode compression); + /** * Set pixel data starting at the pixel offset on screen. * * The screen will continuously overwrite more pixel data without regarding the offset, meaning * once the starting row is full, overwriting will continue on column 0. * - * The contained [SPBitVec] is always uncompressed. + * The [`BinaryOperation`] will be applied on the display comparing old and sent bit. * - * The passed [SPBitVec] gets consumed. + * `new_bit = old_bit op sent_bit` * - * Returns: a new [servicepoint::Command::BitmapLinear] instance. + * For example, [`BinaryOperation::Or`] can be used to turn on some pixels without affecting other pixels. + * + * The contained [`BitVecU8Msb0`] is always uncompressed. */ -TypedCommand *sp_command_bitmap_linear(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); - -/** - * Set pixel data according to an and-mask starting at the offset. - * - * The screen will continuously overwrite more pixel data without regarding the offset, meaning - * once the starting row is full, overwriting will continue on column 0. - * - * The contained [SPBitVec] is always uncompressed. - * - * The passed [SPBitVec] gets consumed. - * - * Returns: a new [servicepoint::Command::BitmapLinearAnd] instance. - */ -TypedCommand *sp_command_bitmap_linear_and(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); - -/** - * Set pixel data according to an or-mask starting at the offset. - * - * The screen will continuously overwrite more pixel data without regarding the offset, meaning - * once the starting row is full, overwriting will continue on column 0. - * - * The contained [SPBitVec] is always uncompressed. - * - * The passed [SPBitVec] gets consumed. - * - * Returns: a new [servicepoint::Command::BitmapLinearOr] instance. - */ -TypedCommand *sp_command_bitmap_linear_or(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); - -/** - * Sets a window of pixels to the specified values. - * - * The passed [Bitmap] gets consumed. - * - * Returns: a new [servicepoint::Command::BitmapLinearWin] instance. - */ -TypedCommand *sp_command_bitmap_linear_win(size_t x, - size_t y, - Bitmap */*notnull*/ bitmap, - CompressionCode compression); - -/** - * Set pixel data according to a xor-mask starting at the offset. - * - * The screen will continuously overwrite more pixel data without regarding the offset, meaning - * once the starting row is full, overwriting will continue on column 0. - * - * The contained [SPBitVec] is always uncompressed. - * - * The passed [SPBitVec] gets consumed. - * - * Returns: a new [servicepoint::Command::BitmapLinearXor] instance. - */ -TypedCommand *sp_command_bitmap_linear_xor(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); +TypedCommand *sp_command_bitvec(size_t offset, + SPBitVec */*notnull*/ bit_vec, + CompressionCode compression, + BinaryOperation operation); /** * Set the brightness of all tiles to the same value. @@ -885,6 +869,17 @@ TypedCommand */*notnull*/ sp_command_char_brightness(size_t x, size_t y, BrightnessGrid */*notnull*/ grid); +/** + * Show UTF-8 encoded text on the screen. + * + * The passed [CharGrid] gets consumed. + * + * Returns: a new [servicepoint::CharGridCommand] instance. + */ +TypedCommand */*notnull*/ sp_command_char_grid(size_t x, + size_t y, + CharGrid */*notnull*/ grid); + /** * Set all pixels to the off state. * @@ -912,9 +907,9 @@ TypedCommand */*notnull*/ sp_command_clone(TypedCommand */*notnull*/ command); * * The passed [Cp437Grid] gets consumed. * - * Returns: a new [servicepoint::Command::Cp437Data] instance. + * Returns: a new [servicepoint::Cp437GridCommand] instance. */ -TypedCommand */*notnull*/ sp_command_cp437_data(size_t x, +TypedCommand */*notnull*/ sp_command_cp437_grid(size_t x, size_t y, Cp437Grid */*notnull*/ grid); @@ -955,83 +950,6 @@ TypedCommand */*notnull*/ sp_command_hard_reset(void); */ TypedCommand *sp_command_try_from_packet(Packet */*notnull*/ packet); -/** - * Show UTF-8 encoded text on the screen. - * - * The passed [CharGrid] gets consumed. - * - * Returns: a new [servicepoint::Command::Utf8Data] instance. - */ -TypedCommand */*notnull*/ sp_command_utf8_data(size_t x, - size_t y, - CharGrid */*notnull*/ grid); - -/** - * Closes and deallocates a [UdpConnection]. - */ -void sp_connection_free(UdpConnection */*notnull*/ connection); - -/** - * Creates a new instance of [UdpConnection]. - * - * returns: NULL if connection fails, or connected instance - * - * # Examples - * - * ```C - * UdpConnection connection = sp_connection_open("172.23.42.29:2342"); - * if (connection != NULL) - * sp_connection_send_command(connection, sp_command_clear()); - * ``` - */ -UdpConnection *sp_connection_open(char */*notnull*/ host); - -/** - * Creates a new instance of [UdpConnection]. - * - * returns: NULL if connection fails, or connected instance - * - * # Examples - * - * ```C - * UdpConnection connection = sp_connection_open_ipv4(172, 23, 42, 29, 2342); - * if (connection != NULL) - * sp_connection_send_command(connection, sp_command_clear()); - * ``` - */ -UdpConnection *sp_connection_open_ipv4(uint8_t ip1, - uint8_t ip2, - uint8_t ip3, - uint8_t ip4, - uint16_t port); - -/** - * Sends a [TypedCommand] to the display using the [UdpConnection]. - * - * The passed `command` gets consumed. - * - * returns: true in case of success - * - * # Examples - * - * ```C - * sp_connection_send_command(connection, sp_command_clear()); - * sp_connection_send_command(connection, sp_command_brightness(5)); - * ``` - */ -bool sp_connection_send_command(UdpConnection */*notnull*/ connection, - TypedCommand */*notnull*/ command); - -/** - * Sends a [Packet] to the display using the [UdpConnection]. - * - * The passed `packet` gets consumed. - * - * returns: true in case of success - */ -bool sp_connection_send_packet(UdpConnection */*notnull*/ connection, - Packet */*notnull*/ packet); - /** * Clones a [Cp437Grid]. */ @@ -1188,6 +1106,72 @@ void sp_packet_set_payload(Packet */*notnull*/ packet, ByteSlice data); */ Packet *sp_packet_try_load(ByteSlice data); +/** + * Closes and deallocates a [UdpConnection]. + */ +void sp_udp_free(UdpConnection */*notnull*/ connection); + +/** + * Creates a new instance of [UdpConnection]. + * + * returns: NULL if connection fails, or connected instance + * + * # Examples + * + * ```C + * UdpConnection connection = sp_connection_open("172.23.42.29:2342"); + * if (connection != NULL) + * sp_connection_send_command(connection, sp_command_clear()); + * ``` + */ +UdpConnection *sp_udp_open(char */*notnull*/ host); + +/** + * Creates a new instance of [UdpConnection]. + * + * returns: NULL if connection fails, or connected instance + * + * # Examples + * + * ```C + * UdpConnection connection = sp_connection_open_ipv4(172, 23, 42, 29, 2342); + * if (connection != NULL) + * sp_connection_send_command(connection, sp_command_clear()); + * ``` + */ +UdpConnection *sp_udp_open_ipv4(uint8_t ip1, + uint8_t ip2, + uint8_t ip3, + uint8_t ip4, + uint16_t port); + +/** + * Sends a [TypedCommand] to the display using the [UdpConnection]. + * + * The passed `command` gets consumed. + * + * returns: true in case of success + * + * # Examples + * + * ```C + * sp_connection_send_command(connection, sp_command_clear()); + * sp_connection_send_command(connection, sp_command_brightness(5)); + * ``` + */ +bool sp_udp_send_command(UdpConnection */*notnull*/ connection, + TypedCommand */*notnull*/ command); + +/** + * Sends a [Packet] to the display using the [UdpConnection]. + * + * The passed `packet` gets consumed. + * + * returns: true in case of success + */ +bool sp_udp_send_packet(UdpConnection */*notnull*/ connection, + Packet */*notnull*/ packet); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/bitmap.rs b/src/bitmap.rs index f9b6882..d1d8522 100644 --- a/src/bitmap.rs +++ b/src/bitmap.rs @@ -42,7 +42,7 @@ pub unsafe extern "C" fn sp_bitmap_new( /// /// returns: [Bitmap] initialized to all pixels off. #[no_mangle] -pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull { +pub unsafe extern "C" fn sp_bitmap_new_max_sized() -> NonNull { let result = Box::new(Bitmap::max_sized()); NonNull::from(Box::leak(result)) } diff --git a/src/command.rs b/src/command.rs index b867eba..80a2b22 100644 --- a/src/command.rs +++ b/src/command.rs @@ -104,106 +104,15 @@ pub unsafe extern "C" fn sp_command_char_brightness( /// The screen will continuously overwrite more pixel data without regarding the offset, meaning /// once the starting row is full, overwriting will continue on column 0. /// -/// The contained [SPBitVec] is always uncompressed. +/// The [`BinaryOperation`] will be applied on the display comparing old and sent bit. /// -/// The passed [SPBitVec] gets consumed. +/// `new_bit = old_bit op sent_bit` /// -/// Returns: a new [servicepoint::Command::BitmapLinear] instance. +/// For example, [`BinaryOperation::Or`] can be used to turn on some pixels without affecting other pixels. +/// +/// The contained [`BitVecU8Msb0`] is always uncompressed. #[no_mangle] -pub unsafe extern "C" fn sp_command_bitmap_linear( - offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { - unsafe { - sp_command_bitmap_linear_internal( - offset, - bit_vec, - compression, - BinaryOperation::Overwrite, - ) - } -} - -/// Set pixel data according to an and-mask starting at the offset. -/// -/// The screen will continuously overwrite more pixel data without regarding the offset, meaning -/// once the starting row is full, overwriting will continue on column 0. -/// -/// The contained [SPBitVec] is always uncompressed. -/// -/// The passed [SPBitVec] gets consumed. -/// -/// Returns: a new [servicepoint::Command::BitmapLinearAnd] instance. -#[no_mangle] -pub unsafe extern "C" fn sp_command_bitmap_linear_and( - offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { - unsafe { - sp_command_bitmap_linear_internal( - offset, - bit_vec, - compression, - BinaryOperation::Xor, - ) - } -} - -/// Set pixel data according to an or-mask starting at the offset. -/// -/// The screen will continuously overwrite more pixel data without regarding the offset, meaning -/// once the starting row is full, overwriting will continue on column 0. -/// -/// The contained [SPBitVec] is always uncompressed. -/// -/// The passed [SPBitVec] gets consumed. -/// -/// Returns: a new [servicepoint::Command::BitmapLinearOr] instance. -#[no_mangle] -pub unsafe extern "C" fn sp_command_bitmap_linear_or( - offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { - unsafe { - sp_command_bitmap_linear_internal( - offset, - bit_vec, - compression, - BinaryOperation::Or, - ) - } -} - -/// Set pixel data according to a xor-mask starting at the offset. -/// -/// The screen will continuously overwrite more pixel data without regarding the offset, meaning -/// once the starting row is full, overwriting will continue on column 0. -/// -/// The contained [SPBitVec] is always uncompressed. -/// -/// The passed [SPBitVec] gets consumed. -/// -/// Returns: a new [servicepoint::Command::BitmapLinearXor] instance. -#[no_mangle] -pub unsafe extern "C" fn sp_command_bitmap_linear_xor( - offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { - unsafe { - sp_command_bitmap_linear_internal( - offset, - bit_vec, - compression, - BinaryOperation::Xor, - ) - } -} - -unsafe fn sp_command_bitmap_linear_internal( +pub unsafe extern "C" fn sp_command_bitvec( offset: usize, bit_vec: NonNull, compression: CompressionCode, @@ -220,7 +129,7 @@ unsafe fn sp_command_bitmap_linear_internal( bitvec: bit_vec.0, compression, } - .into(); + .into(); Box::leak(Box::new(command)) } @@ -228,9 +137,9 @@ unsafe fn sp_command_bitmap_linear_internal( /// /// The passed [Cp437Grid] gets consumed. /// -/// Returns: a new [servicepoint::Command::Cp437Data] instance. +/// Returns: a new [servicepoint::Cp437GridCommand] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_cp437_data( +pub unsafe extern "C" fn sp_command_cp437_grid( x: usize, y: usize, grid: NonNull, @@ -250,9 +159,9 @@ pub unsafe extern "C" fn sp_command_cp437_data( /// /// The passed [CharGrid] gets consumed. /// -/// Returns: a new [servicepoint::Command::Utf8Data] instance. +/// Returns: a new [servicepoint::CharGridCommand] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_utf8_data( +pub unsafe extern "C" fn sp_command_char_grid( x: usize, y: usize, grid: NonNull, @@ -272,9 +181,9 @@ pub unsafe extern "C" fn sp_command_utf8_data( /// /// The passed [Bitmap] gets consumed. /// -/// Returns: a new [servicepoint::Command::BitmapLinearWin] instance. +/// Returns: a new [servicepoint::BitmapCommand] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_bitmap_linear_win( +pub unsafe extern "C" fn sp_command_bitmap( x: usize, y: usize, bitmap: NonNull, diff --git a/src/connection.rs b/src/connection.rs index d6ffb83..b49225d 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -15,7 +15,7 @@ use std::ptr::NonNull; /// sp_connection_send_command(connection, sp_command_clear()); /// ``` #[no_mangle] -pub unsafe extern "C" fn sp_connection_open( +pub unsafe extern "C" fn sp_udp_open( host: NonNull, ) -> *mut UdpConnection { let host = unsafe { CStr::from_ptr(host.as_ptr()) } @@ -41,7 +41,7 @@ pub unsafe extern "C" fn sp_connection_open( /// sp_connection_send_command(connection, sp_command_clear()); /// ``` #[no_mangle] -pub unsafe extern "C" fn sp_connection_open_ipv4( +pub unsafe extern "C" fn sp_udp_open_ipv4( ip1: u8, ip2: u8, ip3: u8, ip4: u8, port: u16, ) -> *mut UdpConnection { @@ -53,29 +53,13 @@ pub unsafe extern "C" fn sp_connection_open_ipv4( Box::into_raw(Box::new(connection)) } -// /// Creates a new instance of [SPUdpConnection] for testing that does not actually send anything. -// /// -// /// returns: a new instance. -// /// -// /// # Safety -// /// -// /// The caller has to make sure that: -// /// -// /// - the returned instance is freed in some way, either by using a consuming function or -// /// by explicitly calling `sp_connection_free`. -// #[no_mangle] -// pub unsafe extern "C" fn sp_connection_fake() -> NonNull { -// let result = Box::new(SPUdpConnection(servicepoint::Connection::Fake)); -// NonNull::from(Box::leak(result)) -// } - /// Sends a [Packet] to the display using the [UdpConnection]. /// /// The passed `packet` gets consumed. /// /// returns: true in case of success #[no_mangle] -pub unsafe extern "C" fn sp_connection_send_packet( +pub unsafe extern "C" fn sp_udp_send_packet( connection: NonNull, packet: NonNull, ) -> bool { @@ -96,7 +80,7 @@ pub unsafe extern "C" fn sp_connection_send_packet( /// sp_connection_send_command(connection, sp_command_brightness(5)); /// ``` #[no_mangle] -pub unsafe extern "C" fn sp_connection_send_command( +pub unsafe extern "C" fn sp_udp_send_command( connection: NonNull, command: NonNull, ) -> bool { @@ -106,7 +90,7 @@ pub unsafe extern "C" fn sp_connection_send_command( /// Closes and deallocates a [UdpConnection]. #[no_mangle] -pub unsafe extern "C" fn sp_connection_free( +pub unsafe extern "C" fn sp_udp_free( connection: NonNull, ) { _ = unsafe { Box::from_raw(connection.as_ptr()) }; From f483b5a2d5e3deea2b43a11b86cf65a20968bcb5 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sat, 12 Apr 2025 18:05:01 +0200 Subject: [PATCH 3/3] unify heap allocation handling --- include/servicepoint.h | 16 ++++----- src/bitmap.rs | 16 ++++----- src/bitvec.rs | 20 ++++------- src/brightness_grid.rs | 12 +++---- src/char_grid.rs | 12 +++---- src/command.rs | 78 +++++++++++++++++++----------------------- src/connection.rs | 18 +++++----- src/cp437_grid.rs | 12 +++---- src/lib.rs | 13 +++++++ src/packet.rs | 14 ++++---- 10 files changed, 101 insertions(+), 110 deletions(-) diff --git a/include/servicepoint.h b/include/servicepoint.h index 8f7ca75..9edeaf9 100644 --- a/include/servicepoint.h +++ b/include/servicepoint.h @@ -851,13 +851,6 @@ TypedCommand *sp_command_bitvec(size_t offset, CompressionCode compression, BinaryOperation operation); -/** - * Set the brightness of all tiles to the same value. - * - * Returns: a new [servicepoint::Command::Brightness] instance. - */ -TypedCommand */*notnull*/ sp_command_brightness(Brightness brightness); - /** * Set the brightness of individual tiles in a rectangular area of the display. * @@ -865,7 +858,7 @@ TypedCommand */*notnull*/ sp_command_brightness(Brightness brightness); * * Returns: a new [servicepoint::Command::CharBrightness] instance. */ -TypedCommand */*notnull*/ sp_command_char_brightness(size_t x, +TypedCommand */*notnull*/ sp_command_brightness_grid(size_t x, size_t y, BrightnessGrid */*notnull*/ grid); @@ -932,6 +925,13 @@ TypedCommand */*notnull*/ sp_command_fade_out(void); */ void sp_command_free(TypedCommand */*notnull*/ command); +/** + * Set the brightness of all tiles to the same value. + * + * Returns: a new [servicepoint::Command::Brightness] instance. + */ +TypedCommand */*notnull*/ sp_command_global_brightness(Brightness brightness); + /** * Kills the udp daemon on the display, which usually results in a restart. * diff --git a/src/bitmap.rs b/src/bitmap.rs index d1d8522..c166881 100644 --- a/src/bitmap.rs +++ b/src/bitmap.rs @@ -1,8 +1,8 @@ +use crate::byte_slice::ByteSlice; +use crate::{heap_drop, heap_move, heap_move_nonnull}; use servicepoint::{Bitmap, DataRef, Grid}; use std::ptr::NonNull; -use crate::byte_slice::ByteSlice; - /// Creates a new [Bitmap] with the specified dimensions. /// /// # Arguments @@ -32,7 +32,7 @@ pub unsafe extern "C" fn sp_bitmap_new( height: usize, ) -> *mut Bitmap { if let Some(bitmap) = Bitmap::new(width, height) { - Box::leak(Box::new(bitmap)) + heap_move(bitmap) } else { std::ptr::null_mut() } @@ -43,8 +43,7 @@ pub unsafe extern "C" fn sp_bitmap_new( /// returns: [Bitmap] initialized to all pixels off. #[no_mangle] pub unsafe extern "C" fn sp_bitmap_new_max_sized() -> NonNull { - let result = Box::new(Bitmap::max_sized()); - NonNull::from(Box::leak(result)) + heap_move_nonnull(Bitmap::max_sized()) } /// Loads a [Bitmap] with the specified dimensions from the provided data. @@ -63,7 +62,7 @@ pub unsafe extern "C" fn sp_bitmap_load( ) -> *mut Bitmap { let data = unsafe { data.as_slice() }; if let Ok(bitmap) = Bitmap::load(width, height, data) { - Box::leak(Box::new(bitmap)) + heap_move(bitmap) } else { std::ptr::null_mut() } @@ -74,14 +73,13 @@ pub unsafe extern "C" fn sp_bitmap_load( pub unsafe extern "C" fn sp_bitmap_clone( bitmap: NonNull, ) -> NonNull { - let result = Box::new(unsafe { bitmap.as_ref().clone() }); - NonNull::from(Box::leak(result)) + heap_move_nonnull(unsafe { bitmap.as_ref().clone() }) } /// Deallocates a [Bitmap]. #[no_mangle] pub unsafe extern "C" fn sp_bitmap_free(bitmap: NonNull) { - _ = unsafe { Box::from_raw(bitmap.as_ptr()) }; + unsafe { heap_drop(bitmap) } } /// Gets the current value at the specified position in the [Bitmap]. diff --git a/src/bitvec.rs b/src/bitvec.rs index f87423d..e5ce720 100644 --- a/src/bitvec.rs +++ b/src/bitvec.rs @@ -1,6 +1,6 @@ -use crate::ByteSlice; -use std::ptr::NonNull; +use crate::{heap_drop, heap_move_nonnull, ByteSlice}; use servicepoint::BitVecU8Msb0; +use std::ptr::NonNull; /// A vector of bits /// @@ -31,21 +31,16 @@ impl Clone for SPBitVec { /// - when `size` is not divisible by 8. #[no_mangle] pub unsafe extern "C" fn sp_bitvec_new(size: usize) -> NonNull { - let result = - Box::new(SPBitVec(BitVecU8Msb0::repeat(false, size))); - NonNull::from(Box::leak(result)) + heap_move_nonnull(SPBitVec(BitVecU8Msb0::repeat(false, size))) } /// Interpret the data as a series of bits and load then into a new [SPBitVec] instance. /// /// returns: [SPBitVec] instance containing data. #[no_mangle] -pub unsafe extern "C" fn sp_bitvec_load( - data: ByteSlice, -) -> NonNull { +pub unsafe extern "C" fn sp_bitvec_load(data: ByteSlice) -> NonNull { let data = unsafe { data.as_slice() }; - let result = Box::new(SPBitVec(BitVecU8Msb0::from_slice(data))); - NonNull::from(Box::leak(result)) + heap_move_nonnull(SPBitVec(BitVecU8Msb0::from_slice(data))) } /// Clones a [SPBitVec]. @@ -53,14 +48,13 @@ pub unsafe extern "C" fn sp_bitvec_load( pub unsafe extern "C" fn sp_bitvec_clone( bit_vec: NonNull, ) -> NonNull { - let result = Box::new(unsafe { bit_vec.as_ref().clone() }); - NonNull::from(Box::leak(result)) + heap_move_nonnull(unsafe { bit_vec.as_ref().clone() }) } /// Deallocates a [SPBitVec]. #[no_mangle] pub unsafe extern "C" fn sp_bitvec_free(bit_vec: NonNull) { - _ = unsafe { Box::from_raw(bit_vec.as_ptr()) }; + unsafe { heap_drop(bit_vec) } } /// Gets the value of a bit from the [SPBitVec]. diff --git a/src/brightness_grid.rs b/src/brightness_grid.rs index 5cd7a16..a283d0a 100644 --- a/src/brightness_grid.rs +++ b/src/brightness_grid.rs @@ -1,4 +1,4 @@ -use crate::ByteSlice; +use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; use servicepoint::{Brightness, BrightnessGrid, ByteGrid, DataRef, Grid}; use std::mem::transmute; use std::ptr::NonNull; @@ -25,8 +25,7 @@ pub unsafe extern "C" fn sp_brightness_grid_new( width: usize, height: usize, ) -> NonNull { - let result = Box::new(BrightnessGrid::new(width, height)); - NonNull::from(Box::leak(result)) + heap_move_nonnull(BrightnessGrid::new(width, height)) } /// Loads a [BrightnessGrid] with the specified dimensions from the provided data. @@ -44,7 +43,7 @@ pub unsafe extern "C" fn sp_brightness_grid_load( Some(grid) => grid, }; if let Ok(grid) = BrightnessGrid::try_from(grid) { - Box::leak(Box::new(grid)) + heap_move(grid) } else { std::ptr::null_mut() } @@ -55,8 +54,7 @@ pub unsafe extern "C" fn sp_brightness_grid_load( pub unsafe extern "C" fn sp_brightness_grid_clone( brightness_grid: NonNull, ) -> NonNull { - let result = Box::new(unsafe { brightness_grid.as_ref().clone() }); - NonNull::from(Box::leak(result)) + heap_move_nonnull(unsafe { brightness_grid.as_ref().clone() }) } /// Deallocates a [BrightnessGrid]. @@ -64,7 +62,7 @@ pub unsafe extern "C" fn sp_brightness_grid_clone( pub unsafe extern "C" fn sp_brightness_grid_free( brightness_grid: NonNull, ) { - _ = unsafe { Box::from_raw(brightness_grid.as_ptr()) }; + unsafe { heap_drop(brightness_grid) } } /// Gets the current value at the specified position. diff --git a/src/char_grid.rs b/src/char_grid.rs index a287d70..cdcc4b5 100644 --- a/src/char_grid.rs +++ b/src/char_grid.rs @@ -1,4 +1,4 @@ -use crate::ByteSlice; +use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; use servicepoint::{CharGrid, Grid}; use std::ptr::NonNull; @@ -19,8 +19,7 @@ pub unsafe extern "C" fn sp_char_grid_new( width: usize, height: usize, ) -> NonNull { - let result = Box::new(CharGrid::new(width, height)); - NonNull::from(Box::leak(result)) + heap_move_nonnull(CharGrid::new(width, height)) } /// Loads a [CharGrid] with the specified dimensions from the provided data. @@ -34,7 +33,7 @@ pub unsafe extern "C" fn sp_char_grid_load( ) -> *mut CharGrid { let data = unsafe { data.as_slice() }; if let Ok(grid) = CharGrid::load_utf8(width, height, data.to_vec()) { - Box::leak(Box::new(grid)) + heap_move(grid) } else { std::ptr::null_mut() } @@ -45,14 +44,13 @@ pub unsafe extern "C" fn sp_char_grid_load( pub unsafe extern "C" fn sp_char_grid_clone( char_grid: NonNull, ) -> NonNull { - let result = unsafe { char_grid.as_ref().clone() }; - NonNull::from(Box::leak(Box::new(result))) + heap_move_nonnull(unsafe { char_grid.as_ref().clone() }) } /// Deallocates a [CharGrid]. #[no_mangle] pub unsafe extern "C" fn sp_char_grid_free(char_grid: NonNull) { - _ = unsafe { Box::from_raw(char_grid.as_ptr()) }; + unsafe { heap_drop(char_grid) } } /// Returns the current value at the specified position. diff --git a/src/command.rs b/src/command.rs index 80a2b22..32d5acd 100644 --- a/src/command.rs +++ b/src/command.rs @@ -1,5 +1,8 @@ -use crate::SPBitVec; -use servicepoint::{BinaryOperation, Bitmap, Brightness, BrightnessGrid, CharGrid, CompressionCode, Cp437Grid, GlobalBrightnessCommand, Packet, TypedCommand}; +use crate::{heap_drop, heap_move, heap_move_nonnull, SPBitVec}; +use servicepoint::{ + BinaryOperation, Bitmap, Brightness, BrightnessGrid, CharGrid, + CompressionCode, Cp437Grid, GlobalBrightnessCommand, Packet, TypedCommand, +}; use std::ptr::NonNull; /// Tries to turn a [Packet] into a [TypedCommand]. @@ -14,7 +17,7 @@ pub unsafe extern "C" fn sp_command_try_from_packet( let packet = *unsafe { Box::from_raw(packet.as_ptr()) }; match servicepoint::TypedCommand::try_from(packet) { Err(_) => std::ptr::null_mut(), - Ok(command) => Box::into_raw(Box::new(command)), + Ok(command) => heap_move(command), } } @@ -25,8 +28,7 @@ pub unsafe extern "C" fn sp_command_try_from_packet( pub unsafe extern "C" fn sp_command_clone( command: NonNull, ) -> NonNull { - let result = Box::new(unsafe { command.as_ref().clone() }); - NonNull::from(Box::leak(result)) + heap_move_nonnull(unsafe { command.as_ref().clone() }) } /// Set all pixels to the off state. @@ -42,8 +44,7 @@ pub unsafe extern "C" fn sp_command_clone( /// ``` #[no_mangle] pub unsafe extern "C" fn sp_command_clear() -> NonNull { - let result = Box::new(servicepoint::ClearCommand.into()); - NonNull::from(Box::leak(result)) + heap_move_nonnull(servicepoint::ClearCommand.into()) } /// Kills the udp daemon on the display, which usually results in a restart. @@ -53,8 +54,7 @@ pub unsafe extern "C" fn sp_command_clear() -> NonNull { /// Returns: a new [servicepoint::Command::HardReset] instance. #[no_mangle] pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull { - let result = Box::new(servicepoint::HardResetCommand.into()); - NonNull::from(Box::leak(result)) + heap_move_nonnull(servicepoint::HardResetCommand.into()) } /// A yet-to-be-tested command. @@ -62,19 +62,17 @@ pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull { /// Returns: a new [servicepoint::Command::FadeOut] instance. #[no_mangle] pub unsafe extern "C" fn sp_command_fade_out() -> NonNull { - let result = Box::new(servicepoint::FadeOutCommand.into()); - NonNull::from(Box::leak(result)) + heap_move_nonnull(servicepoint::FadeOutCommand.into()) } /// Set the brightness of all tiles to the same value. /// /// Returns: a new [servicepoint::Command::Brightness] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_brightness( +pub unsafe extern "C" fn sp_command_global_brightness( brightness: Brightness, ) -> NonNull { - let result = Box::new(GlobalBrightnessCommand::from(brightness).into()); - NonNull::from(Box::leak(result)) + heap_move_nonnull(GlobalBrightnessCommand::from(brightness).into()) } /// Set the brightness of individual tiles in a rectangular area of the display. @@ -83,20 +81,18 @@ pub unsafe extern "C" fn sp_command_brightness( /// /// Returns: a new [servicepoint::Command::CharBrightness] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_char_brightness( +pub unsafe extern "C" fn sp_command_brightness_grid( x: usize, y: usize, grid: NonNull, ) -> NonNull { let grid = unsafe { *Box::from_raw(grid.as_ptr()) }; - let result = Box::new( - servicepoint::BrightnessGridCommand { - origin: servicepoint::Origin::new(x, y), - grid, - } - .into(), - ); - NonNull::from(Box::leak(result)) + let result = servicepoint::BrightnessGridCommand { + origin: servicepoint::Origin::new(x, y), + grid, + } + .into(); + heap_move_nonnull(result) } /// Set pixel data starting at the pixel offset on screen. @@ -129,8 +125,8 @@ pub unsafe extern "C" fn sp_command_bitvec( bitvec: bit_vec.0, compression, } - .into(); - Box::leak(Box::new(command)) + .into(); + heap_move(command) } /// Show codepage 437 encoded text on the screen. @@ -145,14 +141,12 @@ pub unsafe extern "C" fn sp_command_cp437_grid( grid: NonNull, ) -> NonNull { let grid = *unsafe { Box::from_raw(grid.as_ptr()) }; - let result = Box::new( - servicepoint::Cp437GridCommand { - origin: servicepoint::Origin::new(x, y), - grid, - } - .into(), - ); - NonNull::from(Box::leak(result)) + let result = servicepoint::Cp437GridCommand { + origin: servicepoint::Origin::new(x, y), + grid, + } + .into(); + heap_move_nonnull(result) } /// Show UTF-8 encoded text on the screen. @@ -167,14 +161,12 @@ pub unsafe extern "C" fn sp_command_char_grid( grid: NonNull, ) -> NonNull { let grid = unsafe { *Box::from_raw(grid.as_ptr()) }; - let result = Box::new( - servicepoint::CharGridCommand { - origin: servicepoint::Origin::new(x, y), - grid, - } - .into(), - ); - NonNull::from(Box::leak(result)) + let result = servicepoint::CharGridCommand { + origin: servicepoint::Origin::new(x, y), + grid, + } + .into(); + heap_move_nonnull(result) } /// Sets a window of pixels to the specified values. @@ -200,7 +192,7 @@ pub unsafe extern "C" fn sp_command_bitmap( compression, } .into(); - Box::leak(Box::new(command)) + heap_move(command) } /// Deallocates a [TypedCommand]. @@ -213,5 +205,5 @@ pub unsafe extern "C" fn sp_command_bitmap( /// ``` #[no_mangle] pub unsafe extern "C" fn sp_command_free(command: NonNull) { - _ = unsafe { Box::from_raw(command.as_ptr()) }; + unsafe { heap_drop(command) } } diff --git a/src/connection.rs b/src/connection.rs index b49225d..7b29e29 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,3 +1,4 @@ +use crate::{heap_drop, heap_move}; use servicepoint::{Connection, Packet, TypedCommand, UdpConnection}; use std::ffi::{c_char, CStr}; use std::net::{Ipv4Addr, SocketAddrV4}; @@ -26,7 +27,7 @@ pub unsafe extern "C" fn sp_udp_open( Ok(value) => value, }; - Box::into_raw(Box::new(connection)) + heap_move(connection) } /// Creates a new instance of [UdpConnection]. @@ -42,15 +43,18 @@ pub unsafe extern "C" fn sp_udp_open( /// ``` #[no_mangle] pub unsafe extern "C" fn sp_udp_open_ipv4( - ip1: u8, ip2: u8, ip3: u8, ip4: u8, + ip1: u8, + ip2: u8, + ip3: u8, + ip4: u8, port: u16, ) -> *mut UdpConnection { - let addr = SocketAddrV4::new(Ipv4Addr::from( [ip1, ip2, ip3, ip4]), port); + let addr = SocketAddrV4::new(Ipv4Addr::from([ip1, ip2, ip3, ip4]), port); let connection = match UdpConnection::open(addr) { Err(_) => return std::ptr::null_mut(), Ok(value) => value, }; - Box::into_raw(Box::new(connection)) + heap_move(connection) } /// Sends a [Packet] to the display using the [UdpConnection]. @@ -90,8 +94,6 @@ pub unsafe extern "C" fn sp_udp_send_command( /// Closes and deallocates a [UdpConnection]. #[no_mangle] -pub unsafe extern "C" fn sp_udp_free( - connection: NonNull, -) { - _ = unsafe { Box::from_raw(connection.as_ptr()) }; +pub unsafe extern "C" fn sp_udp_free(connection: NonNull) { + unsafe { heap_drop(connection) } } diff --git a/src/cp437_grid.rs b/src/cp437_grid.rs index 3904354..e22a0ed 100644 --- a/src/cp437_grid.rs +++ b/src/cp437_grid.rs @@ -1,4 +1,4 @@ -use crate::ByteSlice; +use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; use servicepoint::{Cp437Grid, DataRef, Grid}; use std::ptr::NonNull; @@ -10,8 +10,7 @@ pub unsafe extern "C" fn sp_cp437_grid_new( width: usize, height: usize, ) -> NonNull { - let result = Box::new(Cp437Grid::new(width, height)); - NonNull::from(Box::leak(result)) + heap_move_nonnull(Cp437Grid::new(width, height)) } /// Loads a [Cp437Grid] with the specified dimensions from the provided data. @@ -24,7 +23,7 @@ pub unsafe extern "C" fn sp_cp437_grid_load( let data = unsafe { data.as_slice() }; let grid = Cp437Grid::load(width, height, data); if let Some(grid) = grid { - Box::leak(Box::new(grid)) + heap_move(grid) } else { std::ptr::null_mut() } @@ -35,14 +34,13 @@ pub unsafe extern "C" fn sp_cp437_grid_load( pub unsafe extern "C" fn sp_cp437_grid_clone( cp437_grid: NonNull, ) -> NonNull { - let result = Box::new(unsafe { cp437_grid.as_ref().clone() }); - NonNull::from(Box::leak(result)) + heap_move_nonnull(unsafe { cp437_grid.as_ref().clone() }) } /// Deallocates a [Cp437Grid]. #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: NonNull) { - _ = unsafe { Box::from_raw(cp437_grid.as_ptr()) }; + unsafe { heap_drop(cp437_grid) } } /// Gets the current value at the specified position. diff --git a/src/lib.rs b/src/lib.rs index 4d4e386..f90e93d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,7 @@ pub use crate::command::*; pub use crate::connection::*; pub use crate::cp437_grid::*; pub use crate::packet::*; +use std::ptr::NonNull; mod bitmap; mod bitvec; @@ -49,3 +50,15 @@ use std::time::Duration; /// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets. pub const SP_FRAME_PACING_MS: u128 = Duration::from_millis(30).as_millis(); + +pub(crate) fn heap_move(x: T) -> *mut T { + Box::into_raw(Box::new(x)) +} + +pub(crate) fn heap_move_nonnull(x: T) -> NonNull { + NonNull::from(Box::leak(Box::new(x))) +} + +pub(crate) unsafe fn heap_drop(x: NonNull) { + drop(unsafe { Box::from_raw(x.as_ptr()) }); +} diff --git a/src/packet.rs b/src/packet.rs index 996c83d..a9def67 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,4 +1,4 @@ -use crate::ByteSlice; +use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; use servicepoint::{Header, Packet, TypedCommand}; use std::ptr::NonNull; @@ -12,7 +12,7 @@ pub unsafe extern "C" fn sp_packet_from_command( ) -> *mut Packet { let command = unsafe { *Box::from_raw(command.as_ptr()) }; if let Ok(packet) = command.try_into() { - Box::leak(Box::new(packet)) + heap_move(packet) } else { std::ptr::null_mut() } @@ -26,7 +26,7 @@ pub unsafe extern "C" fn sp_packet_try_load(data: ByteSlice) -> *mut Packet { let data = unsafe { data.as_slice() }; match servicepoint::Packet::try_from(data) { Err(_) => std::ptr::null_mut(), - Ok(packet) => Box::into_raw(Box::new(packet)), + Ok(packet) => heap_move(packet), } } @@ -45,8 +45,7 @@ pub unsafe extern "C" fn sp_packet_from_parts( Vec::from(payload) }; - let packet = Box::new(Packet { header, payload }); - NonNull::from(Box::leak(packet)) + heap_move_nonnull(Packet { header, payload }) } /// Returns a pointer to the header field of the provided packet. @@ -100,12 +99,11 @@ pub unsafe extern "C" fn sp_packet_serialize_to( pub unsafe extern "C" fn sp_packet_clone( packet: NonNull, ) -> NonNull { - let result = Box::new(unsafe { packet.as_ref().clone() }); - NonNull::from(Box::leak(result)) + heap_move_nonnull(unsafe { packet.as_ref().clone() }) } /// Deallocates a [Packet]. #[no_mangle] pub unsafe extern "C" fn sp_packet_free(packet: NonNull) { - _ = unsafe { Box::from_raw(packet.as_ptr()) } + unsafe { heap_drop(packet) } }