diff --git a/Cargo.lock b/Cargo.lock index f87ecea..c0b11c4 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#531d4e6b4a368dc126cab9dc12b64d2ca8a81694" +source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#971bee5065139f220022e8108cfaa9c263b8a8a0" dependencies = [ "bitvec", "bzip2", diff --git a/example/Makefile b/example/Makefile index d3f346f..e7d858f 100644 --- a/example/Makefile +++ b/example/Makefile @@ -63,19 +63,11 @@ out/example_unstripped: dependencies main.c $(CCFLAGS) \ -o out/example_unstripped out/example: out/example_unstripped - 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 + 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 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 9c0ec9e..4e63dec 100644 --- a/example/main.c +++ b/example/main.c @@ -2,7 +2,7 @@ #include "servicepoint.h" int main(void) { - UdpConnection *connection = sp_udp_open_ipv4(127, 0, 0, 1, 2342); + UdpConnection *connection = sp_connection_open("localhost:2342"); if (connection == NULL) return 1; @@ -12,17 +12,17 @@ int main(void) { sp_bitmap_fill(pixels, true); - TypedCommand *command = sp_command_bitmap(0, 0, pixels, COMPRESSION_CODE_UNCOMPRESSED); + TypedCommand *command = sp_command_bitmap_linear_win(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_udp_send_packet(connection, packet); + sp_connection_send_packet(connection, packet); - sp_udp_free(connection); + sp_connection_free(connection); return 0; } diff --git a/include/servicepoint.h b/include/servicepoint.h index 9edeaf9..dbce14d 100644 --- a/include/servicepoint.h +++ b/include/servicepoint.h @@ -66,35 +66,6 @@ */ #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. * @@ -457,7 +428,7 @@ Bitmap *sp_bitmap_new(size_t width, size_t height); * * returns: [Bitmap] initialized to all pixels off. */ -Bitmap */*notnull*/ sp_bitmap_new_max_sized(void); +Bitmap */*notnull*/ sp_bitmap_new_screen_sized(void); /** * Sets the value of the specified position in the [Bitmap]. @@ -820,36 +791,88 @@ 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 [`BinaryOperation`] will be applied on the display comparing old and sent bit. + * The contained [SPBitVec] is always uncompressed. * - * `new_bit = old_bit op sent_bit` + * The passed [SPBitVec] gets consumed. * - * For example, [`BinaryOperation::Or`] can be used to turn on some pixels without affecting other pixels. - * - * The contained [`BitVecU8Msb0`] is always uncompressed. + * Returns: a new [servicepoint::Command::BitmapLinear] instance. */ -TypedCommand *sp_command_bitvec(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression, - BinaryOperation operation); +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); + +/** + * 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. @@ -858,21 +881,10 @@ TypedCommand *sp_command_bitvec(size_t offset, * * Returns: a new [servicepoint::Command::CharBrightness] instance. */ -TypedCommand */*notnull*/ sp_command_brightness_grid(size_t x, +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. * @@ -900,9 +912,9 @@ TypedCommand */*notnull*/ sp_command_clone(TypedCommand */*notnull*/ command); * * The passed [Cp437Grid] gets consumed. * - * Returns: a new [servicepoint::Cp437GridCommand] instance. + * Returns: a new [servicepoint::Command::Cp437Data] instance. */ -TypedCommand */*notnull*/ sp_command_cp437_grid(size_t x, +TypedCommand */*notnull*/ sp_command_cp437_data(size_t x, size_t y, Cp437Grid */*notnull*/ grid); @@ -925,13 +937,6 @@ 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. * @@ -950,6 +955,64 @@ 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 + * CConnection 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); + +/** + * 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]. */ @@ -1106,72 +1169,6 @@ 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 c166881..f9b6882 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) { - heap_move(bitmap) + Box::leak(Box::new(bitmap)) } else { std::ptr::null_mut() } @@ -42,8 +42,9 @@ 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 { - heap_move_nonnull(Bitmap::max_sized()) +pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull { + let result = Box::new(Bitmap::max_sized()); + NonNull::from(Box::leak(result)) } /// Loads a [Bitmap] with the specified dimensions from the provided data. @@ -62,7 +63,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) { - heap_move(bitmap) + Box::leak(Box::new(bitmap)) } else { std::ptr::null_mut() } @@ -73,13 +74,14 @@ pub unsafe extern "C" fn sp_bitmap_load( pub unsafe extern "C" fn sp_bitmap_clone( bitmap: NonNull, ) -> NonNull { - heap_move_nonnull(unsafe { bitmap.as_ref().clone() }) + let result = Box::new(unsafe { bitmap.as_ref().clone() }); + NonNull::from(Box::leak(result)) } /// Deallocates a [Bitmap]. #[no_mangle] pub unsafe extern "C" fn sp_bitmap_free(bitmap: NonNull) { - unsafe { heap_drop(bitmap) } + _ = unsafe { Box::from_raw(bitmap.as_ptr()) }; } /// Gets the current value at the specified position in the [Bitmap]. diff --git a/src/bitvec.rs b/src/bitvec.rs index e5ce720..f87423d 100644 --- a/src/bitvec.rs +++ b/src/bitvec.rs @@ -1,6 +1,6 @@ -use crate::{heap_drop, heap_move_nonnull, ByteSlice}; -use servicepoint::BitVecU8Msb0; +use crate::ByteSlice; use std::ptr::NonNull; +use servicepoint::BitVecU8Msb0; /// A vector of bits /// @@ -31,16 +31,21 @@ impl Clone for SPBitVec { /// - when `size` is not divisible by 8. #[no_mangle] pub unsafe extern "C" fn sp_bitvec_new(size: usize) -> NonNull { - heap_move_nonnull(SPBitVec(BitVecU8Msb0::repeat(false, size))) + let result = + Box::new(SPBitVec(BitVecU8Msb0::repeat(false, size))); + NonNull::from(Box::leak(result)) } /// 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() }; - heap_move_nonnull(SPBitVec(BitVecU8Msb0::from_slice(data))) + let result = Box::new(SPBitVec(BitVecU8Msb0::from_slice(data))); + NonNull::from(Box::leak(result)) } /// Clones a [SPBitVec]. @@ -48,13 +53,14 @@ pub unsafe extern "C" fn sp_bitvec_load(data: ByteSlice) -> NonNull { pub unsafe extern "C" fn sp_bitvec_clone( bit_vec: NonNull, ) -> NonNull { - heap_move_nonnull(unsafe { bit_vec.as_ref().clone() }) + let result = Box::new(unsafe { bit_vec.as_ref().clone() }); + NonNull::from(Box::leak(result)) } /// Deallocates a [SPBitVec]. #[no_mangle] pub unsafe extern "C" fn sp_bitvec_free(bit_vec: NonNull) { - unsafe { heap_drop(bit_vec) } + _ = unsafe { Box::from_raw(bit_vec.as_ptr()) }; } /// Gets the value of a bit from the [SPBitVec]. diff --git a/src/brightness_grid.rs b/src/brightness_grid.rs index a283d0a..5cd7a16 100644 --- a/src/brightness_grid.rs +++ b/src/brightness_grid.rs @@ -1,4 +1,4 @@ -use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; +use crate::ByteSlice; use servicepoint::{Brightness, BrightnessGrid, ByteGrid, DataRef, Grid}; use std::mem::transmute; use std::ptr::NonNull; @@ -25,7 +25,8 @@ pub unsafe extern "C" fn sp_brightness_grid_new( width: usize, height: usize, ) -> NonNull { - heap_move_nonnull(BrightnessGrid::new(width, height)) + let result = Box::new(BrightnessGrid::new(width, height)); + NonNull::from(Box::leak(result)) } /// Loads a [BrightnessGrid] with the specified dimensions from the provided data. @@ -43,7 +44,7 @@ pub unsafe extern "C" fn sp_brightness_grid_load( Some(grid) => grid, }; if let Ok(grid) = BrightnessGrid::try_from(grid) { - heap_move(grid) + Box::leak(Box::new(grid)) } else { std::ptr::null_mut() } @@ -54,7 +55,8 @@ pub unsafe extern "C" fn sp_brightness_grid_load( pub unsafe extern "C" fn sp_brightness_grid_clone( brightness_grid: NonNull, ) -> NonNull { - heap_move_nonnull(unsafe { brightness_grid.as_ref().clone() }) + let result = Box::new(unsafe { brightness_grid.as_ref().clone() }); + NonNull::from(Box::leak(result)) } /// Deallocates a [BrightnessGrid]. @@ -62,7 +64,7 @@ pub unsafe extern "C" fn sp_brightness_grid_clone( pub unsafe extern "C" fn sp_brightness_grid_free( brightness_grid: NonNull, ) { - unsafe { heap_drop(brightness_grid) } + _ = unsafe { Box::from_raw(brightness_grid.as_ptr()) }; } /// Gets the current value at the specified position. diff --git a/src/char_grid.rs b/src/char_grid.rs index cdcc4b5..a287d70 100644 --- a/src/char_grid.rs +++ b/src/char_grid.rs @@ -1,4 +1,4 @@ -use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; +use crate::ByteSlice; use servicepoint::{CharGrid, Grid}; use std::ptr::NonNull; @@ -19,7 +19,8 @@ pub unsafe extern "C" fn sp_char_grid_new( width: usize, height: usize, ) -> NonNull { - heap_move_nonnull(CharGrid::new(width, height)) + let result = Box::new(CharGrid::new(width, height)); + NonNull::from(Box::leak(result)) } /// Loads a [CharGrid] with the specified dimensions from the provided data. @@ -33,7 +34,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()) { - heap_move(grid) + Box::leak(Box::new(grid)) } else { std::ptr::null_mut() } @@ -44,13 +45,14 @@ pub unsafe extern "C" fn sp_char_grid_load( pub unsafe extern "C" fn sp_char_grid_clone( char_grid: NonNull, ) -> NonNull { - heap_move_nonnull(unsafe { char_grid.as_ref().clone() }) + let result = unsafe { char_grid.as_ref().clone() }; + NonNull::from(Box::leak(Box::new(result))) } /// Deallocates a [CharGrid]. #[no_mangle] pub unsafe extern "C" fn sp_char_grid_free(char_grid: NonNull) { - unsafe { heap_drop(char_grid) } + _ = unsafe { Box::from_raw(char_grid.as_ptr()) }; } /// Returns the current value at the specified position. diff --git a/src/command.rs b/src/command.rs index 32d5acd..b867eba 100644 --- a/src/command.rs +++ b/src/command.rs @@ -1,8 +1,5 @@ -use crate::{heap_drop, heap_move, heap_move_nonnull, SPBitVec}; -use servicepoint::{ - BinaryOperation, Bitmap, Brightness, BrightnessGrid, CharGrid, - CompressionCode, Cp437Grid, GlobalBrightnessCommand, Packet, TypedCommand, -}; +use crate::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]. @@ -17,7 +14,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) => heap_move(command), + Ok(command) => Box::into_raw(Box::new(command)), } } @@ -28,7 +25,8 @@ pub unsafe extern "C" fn sp_command_try_from_packet( pub unsafe extern "C" fn sp_command_clone( command: NonNull, ) -> NonNull { - heap_move_nonnull(unsafe { command.as_ref().clone() }) + let result = Box::new(unsafe { command.as_ref().clone() }); + NonNull::from(Box::leak(result)) } /// Set all pixels to the off state. @@ -44,7 +42,8 @@ pub unsafe extern "C" fn sp_command_clone( /// ``` #[no_mangle] pub unsafe extern "C" fn sp_command_clear() -> NonNull { - heap_move_nonnull(servicepoint::ClearCommand.into()) + let result = Box::new(servicepoint::ClearCommand.into()); + NonNull::from(Box::leak(result)) } /// Kills the udp daemon on the display, which usually results in a restart. @@ -54,7 +53,8 @@ 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 { - heap_move_nonnull(servicepoint::HardResetCommand.into()) + let result = Box::new(servicepoint::HardResetCommand.into()); + NonNull::from(Box::leak(result)) } /// A yet-to-be-tested command. @@ -62,17 +62,19 @@ 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 { - heap_move_nonnull(servicepoint::FadeOutCommand.into()) + let result = Box::new(servicepoint::FadeOutCommand.into()); + NonNull::from(Box::leak(result)) } /// 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_global_brightness( +pub unsafe extern "C" fn sp_command_brightness( brightness: Brightness, ) -> NonNull { - heap_move_nonnull(GlobalBrightnessCommand::from(brightness).into()) + let result = Box::new(GlobalBrightnessCommand::from(brightness).into()); + NonNull::from(Box::leak(result)) } /// Set the brightness of individual tiles in a rectangular area of the display. @@ -81,18 +83,20 @@ pub unsafe extern "C" fn sp_command_global_brightness( /// /// Returns: a new [servicepoint::Command::CharBrightness] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_brightness_grid( +pub unsafe extern "C" fn sp_command_char_brightness( x: usize, y: usize, grid: NonNull, ) -> NonNull { let grid = unsafe { *Box::from_raw(grid.as_ptr()) }; - let result = servicepoint::BrightnessGridCommand { - origin: servicepoint::Origin::new(x, y), - grid, - } - .into(); - heap_move_nonnull(result) + let result = Box::new( + servicepoint::BrightnessGridCommand { + origin: servicepoint::Origin::new(x, y), + grid, + } + .into(), + ); + NonNull::from(Box::leak(result)) } /// Set pixel data starting at the pixel offset on screen. @@ -100,15 +104,106 @@ pub unsafe extern "C" fn sp_command_brightness_grid( /// 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 [`BinaryOperation`] will be applied on the display comparing old and sent bit. +/// The contained [SPBitVec] is always uncompressed. /// -/// `new_bit = old_bit op sent_bit` +/// The passed [SPBitVec] gets consumed. /// -/// For example, [`BinaryOperation::Or`] can be used to turn on some pixels without affecting other pixels. -/// -/// The contained [`BitVecU8Msb0`] is always uncompressed. +/// Returns: a new [servicepoint::Command::BitmapLinear] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_bitvec( +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( offset: usize, bit_vec: NonNull, compression: CompressionCode, @@ -126,56 +221,60 @@ pub unsafe extern "C" fn sp_command_bitvec( compression, } .into(); - heap_move(command) + Box::leak(Box::new(command)) } /// Show codepage 437 encoded text on the screen. /// /// The passed [Cp437Grid] gets consumed. /// -/// Returns: a new [servicepoint::Cp437GridCommand] instance. +/// Returns: a new [servicepoint::Command::Cp437Data] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_cp437_grid( +pub unsafe extern "C" fn sp_command_cp437_data( x: usize, y: usize, grid: NonNull, ) -> NonNull { let grid = *unsafe { Box::from_raw(grid.as_ptr()) }; - let result = servicepoint::Cp437GridCommand { - origin: servicepoint::Origin::new(x, y), - grid, - } - .into(); - heap_move_nonnull(result) + let result = Box::new( + servicepoint::Cp437GridCommand { + origin: servicepoint::Origin::new(x, y), + grid, + } + .into(), + ); + NonNull::from(Box::leak(result)) } /// Show UTF-8 encoded text on the screen. /// /// The passed [CharGrid] gets consumed. /// -/// Returns: a new [servicepoint::CharGridCommand] instance. +/// Returns: a new [servicepoint::Command::Utf8Data] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_char_grid( +pub unsafe extern "C" fn sp_command_utf8_data( x: usize, y: usize, grid: NonNull, ) -> NonNull { let grid = unsafe { *Box::from_raw(grid.as_ptr()) }; - let result = servicepoint::CharGridCommand { - origin: servicepoint::Origin::new(x, y), - grid, - } - .into(); - heap_move_nonnull(result) + let result = Box::new( + servicepoint::CharGridCommand { + origin: servicepoint::Origin::new(x, y), + grid, + } + .into(), + ); + NonNull::from(Box::leak(result)) } /// Sets a window of pixels to the specified values. /// /// The passed [Bitmap] gets consumed. /// -/// Returns: a new [servicepoint::BitmapCommand] instance. +/// Returns: a new [servicepoint::Command::BitmapLinearWin] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_bitmap( +pub unsafe extern "C" fn sp_command_bitmap_linear_win( x: usize, y: usize, bitmap: NonNull, @@ -192,7 +291,7 @@ pub unsafe extern "C" fn sp_command_bitmap( compression, } .into(); - heap_move(command) + Box::leak(Box::new(command)) } /// Deallocates a [TypedCommand]. @@ -205,5 +304,5 @@ pub unsafe extern "C" fn sp_command_bitmap( /// ``` #[no_mangle] pub unsafe extern "C" fn sp_command_free(command: NonNull) { - unsafe { heap_drop(command) } + _ = unsafe { Box::from_raw(command.as_ptr()) }; } diff --git a/src/connection.rs b/src/connection.rs index 7b29e29..5feb528 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,7 +1,5 @@ -use crate::{heap_drop, heap_move}; 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]. @@ -11,12 +9,12 @@ use std::ptr::NonNull; /// # Examples /// /// ```C -/// UdpConnection connection = sp_connection_open("172.23.42.29:2342"); +/// CConnection connection = sp_connection_open("172.23.42.29:2342"); /// if (connection != NULL) /// sp_connection_send_command(connection, sp_command_clear()); /// ``` #[no_mangle] -pub unsafe extern "C" fn sp_udp_open( +pub unsafe extern "C" fn sp_connection_open( host: NonNull, ) -> *mut UdpConnection { let host = unsafe { CStr::from_ptr(host.as_ptr()) } @@ -27,35 +25,36 @@ pub unsafe extern "C" fn sp_udp_open( Ok(value) => value, }; - heap_move(connection) + Box::into_raw(Box::new(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_udp_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, - }; - heap_move(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 [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]. /// @@ -63,7 +62,7 @@ pub unsafe extern "C" fn sp_udp_open_ipv4( /// /// returns: true in case of success #[no_mangle] -pub unsafe extern "C" fn sp_udp_send_packet( +pub unsafe extern "C" fn sp_connection_send_packet( connection: NonNull, packet: NonNull, ) -> bool { @@ -84,7 +83,7 @@ pub unsafe extern "C" fn sp_udp_send_packet( /// sp_connection_send_command(connection, sp_command_brightness(5)); /// ``` #[no_mangle] -pub unsafe extern "C" fn sp_udp_send_command( +pub unsafe extern "C" fn sp_connection_send_command( connection: NonNull, command: NonNull, ) -> bool { @@ -94,6 +93,8 @@ 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 { heap_drop(connection) } +pub unsafe extern "C" fn sp_connection_free( + connection: NonNull, +) { + _ = unsafe { Box::from_raw(connection.as_ptr()) }; } diff --git a/src/cp437_grid.rs b/src/cp437_grid.rs index e22a0ed..3904354 100644 --- a/src/cp437_grid.rs +++ b/src/cp437_grid.rs @@ -1,4 +1,4 @@ -use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; +use crate::ByteSlice; use servicepoint::{Cp437Grid, DataRef, Grid}; use std::ptr::NonNull; @@ -10,7 +10,8 @@ pub unsafe extern "C" fn sp_cp437_grid_new( width: usize, height: usize, ) -> NonNull { - heap_move_nonnull(Cp437Grid::new(width, height)) + let result = Box::new(Cp437Grid::new(width, height)); + NonNull::from(Box::leak(result)) } /// Loads a [Cp437Grid] with the specified dimensions from the provided data. @@ -23,7 +24,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 { - heap_move(grid) + Box::leak(Box::new(grid)) } else { std::ptr::null_mut() } @@ -34,13 +35,14 @@ pub unsafe extern "C" fn sp_cp437_grid_load( pub unsafe extern "C" fn sp_cp437_grid_clone( cp437_grid: NonNull, ) -> NonNull { - heap_move_nonnull(unsafe { cp437_grid.as_ref().clone() }) + let result = Box::new(unsafe { cp437_grid.as_ref().clone() }); + NonNull::from(Box::leak(result)) } /// Deallocates a [Cp437Grid]. #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: NonNull) { - unsafe { heap_drop(cp437_grid) } + _ = unsafe { Box::from_raw(cp437_grid.as_ptr()) }; } /// Gets the current value at the specified position. diff --git a/src/lib.rs b/src/lib.rs index f90e93d..4d4e386 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,6 @@ 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; @@ -50,15 +49,3 @@ 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 a9def67..996c83d 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,4 +1,4 @@ -use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; +use crate::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() { - heap_move(packet) + Box::leak(Box::new(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) => heap_move(packet), + Ok(packet) => Box::into_raw(Box::new(packet)), } } @@ -45,7 +45,8 @@ pub unsafe extern "C" fn sp_packet_from_parts( Vec::from(payload) }; - heap_move_nonnull(Packet { header, payload }) + let packet = Box::new(Packet { header, payload }); + NonNull::from(Box::leak(packet)) } /// Returns a pointer to the header field of the provided packet. @@ -99,11 +100,12 @@ pub unsafe extern "C" fn sp_packet_serialize_to( pub unsafe extern "C" fn sp_packet_clone( packet: NonNull, ) -> NonNull { - heap_move_nonnull(unsafe { packet.as_ref().clone() }) + let result = Box::new(unsafe { packet.as_ref().clone() }); + NonNull::from(Box::leak(result)) } /// Deallocates a [Packet]. #[no_mangle] pub unsafe extern "C" fn sp_packet_free(packet: NonNull) { - unsafe { heap_drop(packet) } + _ = unsafe { Box::from_raw(packet.as_ptr()) } }