diff --git a/include/servicepoint.h b/include/servicepoint.h index 68d4c57..e001ddd 100644 --- a/include/servicepoint.h +++ b/include/servicepoint.h @@ -1,7 +1,7 @@ #ifndef SERVICEPOINT_BINDINGS_C #define SERVICEPOINT_BINDINGS_C -/* Generated with cbindgen:0.28.0 */ +/* Generated with cbindgen:0.29.0 */ /* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ @@ -633,6 +633,12 @@ typedef struct Header { extern "C" { #endif // __cplusplus +/** + * Call this function at the beginning of main to enable rust logging controlled by the + * `RUST_LOG` environment variable. See [env_logger](https://docs.rs/env_logger/latest/env_logger/). + */ +void init_env_logger(void); + /** *Clones a [`Bitmap`] instance. * @@ -1248,14 +1254,14 @@ void sp_cmd_bitmap_free(struct BitmapCommand */*notnull*/ instance); struct BitmapCommand */*notnull*/ sp_cmd_bitmap_from_bitmap(struct Bitmap */*notnull*/ bitmap); /** - * Gets a reference to the field `bitmap` of the [`servicepoint::BitmapCommand`]. + * Returns a pointer to the provided `BitmapCommand`. * - * - The returned reference inherits the lifetime of object in which it is contained. + * # Safety + * + * - The returned bitmap inherits the lifetime of the command in which it is contained. * - The returned pointer may not be used in a function that consumes the instance, e.g. to create a command. - * - * This function is part of the sp_cmd_bitmap module. */ -struct Bitmap */*notnull*/ sp_cmd_bitmap_get_bitmap_mut(struct BitmapCommand */*notnull*/ instance); +struct Bitmap */*notnull*/ sp_cmd_bitmap_get(struct BitmapCommand */*notnull*/ command); /** * Gets the value of field `compression` of the [`servicepoint::BitmapCommand`]. @@ -1265,9 +1271,7 @@ struct Bitmap */*notnull*/ sp_cmd_bitmap_get_bitmap_mut(struct BitmapCommand */* CompressionCode sp_cmd_bitmap_get_compression(struct BitmapCommand */*notnull*/ instance); /** - * Reads the origin field of the [`BitmapCommand`]. - * - * This function is part of the sp_cmd_bitmap module. + * Reads the origin field of the [BitmapCommand]. */ void sp_cmd_bitmap_get_origin(struct BitmapCommand */*notnull*/ command, size_t */*notnull*/ origin_x, @@ -1288,13 +1292,10 @@ struct BitmapCommand */*notnull*/ sp_cmd_bitmap_new(struct Bitmap */*notnull*/ b CompressionCode compression); /** - * Sets the value of field `bitmap` of the [`servicepoint::BitmapCommand`]. - * The provided value is moved into the instance, potentially invalidating previously taken references. - * - * This function is part of the sp_cmd_bitmap module. + * Moves the provided [Bitmap] to be contained in the [BitmapCommand]. */ -void sp_cmd_bitmap_set_bitmap(struct BitmapCommand */*notnull*/ instance, - struct Bitmap */*notnull*/ value); +void sp_cmd_bitmap_set(struct BitmapCommand */*notnull*/ command, + struct Bitmap */*notnull*/ bitmap); /** * Sets the value of field `compression` of the [`servicepoint::BitmapCommand`]. @@ -1305,9 +1306,7 @@ void sp_cmd_bitmap_set_compression(struct BitmapCommand */*notnull*/ instance, CompressionCode value); /** - * Overwrites the origin field of the [`BitmapCommand`]. - * - * This function is part of the sp_cmd_bitmap module. + * Overwrites the origin field of the [BitmapCommand]. */ void sp_cmd_bitmap_set_origin(struct BitmapCommand */*notnull*/ command, size_t origin_x, @@ -1337,14 +1336,9 @@ struct BitVecCommand */*notnull*/ sp_cmd_bitvec_clone(struct BitVecCommand */*no void sp_cmd_bitvec_free(struct BitVecCommand */*notnull*/ instance); /** - * Gets a reference to the field `bitvec` of the [`servicepoint::BitVecCommand`]. - * - * - The returned reference inherits the lifetime of object in which it is contained. - * - The returned pointer may not be used in a function that consumes the instance, e.g. to create a command. - * - * This function is part of the sp_cmd_bitvec module. + * Returns a pointer to the [BitVec] contained in the [BitVecCommand]. */ -BitVec */*notnull*/ sp_cmd_bitvec_get_bitvec_mut(struct BitVecCommand */*notnull*/ instance); +BitVec *sp_cmd_bitvec_get(struct BitVecCommand */*notnull*/ command); /** * Gets the value of field `compression` of the [`servicepoint::BitVecCommand`]. @@ -1389,13 +1383,10 @@ struct BitVecCommand */*notnull*/ sp_cmd_bitvec_new(BitVec */*notnull*/ bitvec, CompressionCode compression); /** - * Sets the value of field `bitvec` of the [`servicepoint::BitVecCommand`]. - * The provided value is moved into the instance, potentially invalidating previously taken references. - * - * This function is part of the sp_cmd_bitvec module. + * Moves the provided [BitVec] to be contained in the [BitVecCommand]. */ -void sp_cmd_bitvec_set_bitvec(struct BitVecCommand */*notnull*/ instance, - BitVec */*notnull*/ value); +void sp_cmd_bitvec_set(struct BitVecCommand */*notnull*/ command, + BitVec */*notnull*/ bitvec); /** * Sets the value of field `compression` of the [`servicepoint::BitVecCommand`]. @@ -1498,19 +1489,12 @@ void sp_cmd_brightness_grid_free(struct BrightnessGridCommand */*notnull*/ insta struct BrightnessGridCommand */*notnull*/ sp_cmd_brightness_grid_from_grid(BrightnessGrid */*notnull*/ grid); /** - * Gets a reference to the field `grid` of the [`servicepoint::BrightnessGridCommand`]. - * - * - The returned reference inherits the lifetime of object in which it is contained. - * - The returned pointer may not be used in a function that consumes the instance, e.g. to create a command. - * - * This function is part of the sp_cmd_brightness_grid module. + * Returns a pointer to the [BrightnessGrid] contained in the [BrightnessGridCommand]. */ -BrightnessGrid */*notnull*/ sp_cmd_brightness_grid_get_grid_mut(struct BrightnessGridCommand */*notnull*/ instance); +BrightnessGrid *sp_cmd_brightness_grid_get(struct BrightnessGridCommand */*notnull*/ command); /** - * Reads the origin field of the [`BrightnessGridCommand`]. - * - * This function is part of the sp_cmd_brightness_grid module. + * Overwrites the origin field of the [BrightnessGridCommand]. */ void sp_cmd_brightness_grid_get_origin(struct BrightnessGridCommand */*notnull*/ command, size_t */*notnull*/ origin_x, @@ -1539,18 +1523,13 @@ struct BrightnessGridCommand */*notnull*/ sp_cmd_brightness_grid_new(BrightnessG size_t origin_y); /** - * Sets the value of field `grid` of the [`servicepoint::BrightnessGridCommand`]. - * The provided value is moved into the instance, potentially invalidating previously taken references. - * - * This function is part of the sp_cmd_brightness_grid module. + * Moves the provided [BrightnessGrid] to be contained in the [BrightnessGridCommand]. */ -void sp_cmd_brightness_grid_set_grid(struct BrightnessGridCommand */*notnull*/ instance, - BrightnessGrid */*notnull*/ value); +void sp_cmd_brightness_grid_set(struct BrightnessGridCommand */*notnull*/ command, + BrightnessGrid */*notnull*/ grid); /** - * Overwrites the origin field of the [`BrightnessGridCommand`]. - * - * This function is part of the sp_cmd_brightness_grid module. + * Reads the origin field of the [BrightnessGridCommand]. */ void sp_cmd_brightness_grid_set_origin(struct BrightnessGridCommand */*notnull*/ command, size_t origin_x, @@ -1579,19 +1558,12 @@ void sp_cmd_char_grid_free(struct CharGridCommand */*notnull*/ instance); struct CharGridCommand */*notnull*/ sp_cmd_char_grid_from_grid(CharGrid */*notnull*/ grid); /** - * Gets a reference to the field `grid` of the [`servicepoint::CharGridCommand`]. - * - * - The returned reference inherits the lifetime of object in which it is contained. - * - The returned pointer may not be used in a function that consumes the instance, e.g. to create a command. - * - * This function is part of the sp_cmd_char_grid module. + * Returns a pointer to the [CharGrid] contained in the [CharGridCommand]. */ -CharGrid */*notnull*/ sp_cmd_char_grid_get_grid_mut(struct CharGridCommand */*notnull*/ instance); +CharGrid */*notnull*/ sp_cmd_char_grid_get(struct CharGridCommand */*notnull*/ command); /** - * Reads the origin field of the [`CharGridCommand`]. - * - * This function is part of the sp_cmd_char_grid module. + * Reads the origin field of the [CharGridCommand]. */ void sp_cmd_char_grid_get_origin(struct CharGridCommand */*notnull*/ command, size_t */*notnull*/ origin_x, @@ -1611,18 +1583,13 @@ struct CharGridCommand */*notnull*/ sp_cmd_char_grid_new(CharGrid */*notnull*/ g size_t origin_y); /** - * Sets the value of field `grid` of the [`servicepoint::CharGridCommand`]. - * The provided value is moved into the instance, potentially invalidating previously taken references. - * - * This function is part of the sp_cmd_char_grid module. + * Moves the provided [CharGrid] to be contained in the [CharGridCommand]. */ -void sp_cmd_char_grid_set_grid(struct CharGridCommand */*notnull*/ instance, - CharGrid */*notnull*/ value); +void sp_cmd_char_grid_set(struct CharGridCommand */*notnull*/ command, + CharGrid */*notnull*/ grid); /** - * Overwrites the origin field of the [`CharGridCommand`]. - * - * This function is part of the sp_cmd_char_grid module. + * Overwrites the origin field of the [CharGridCommand]. */ void sp_cmd_char_grid_set_origin(struct CharGridCommand */*notnull*/ command, size_t origin_x, @@ -1649,7 +1616,7 @@ void sp_cmd_clear_free(struct ClearCommand */*notnull*/ instance); * * Does not affect brightness. * - * Returns: a new [`ClearCommand`] instance. + * Returns: a new [ClearCommand] instance. * * This function is part of the sp_cmd_clear module. */ @@ -1678,19 +1645,19 @@ void sp_cmd_cp437_grid_free(struct Cp437GridCommand */*notnull*/ instance); struct Cp437GridCommand */*notnull*/ sp_cmd_cp437_grid_from_grid(Cp437Grid */*notnull*/ grid); /** - * Gets a reference to the field `grid` of the [`servicepoint::Cp437GridCommand`]. + * Show text on the screen. * - * - The returned reference inherits the lifetime of object in which it is contained. - * - The returned pointer may not be used in a function that consumes the instance, e.g. to create a command. + * The text is sent in the form of a 2D grid of [CP-437] encoded characters. + * For sending UTF-8 encoded characters, see [servicepoint::CharGridCommand]. * - * This function is part of the sp_cmd_cp437_grid module. + * [CP-437]: https://en.wikipedia.org/wiki/Code_page_437 */ -Cp437Grid */*notnull*/ sp_cmd_cp437_grid_get_grid_mut(struct Cp437GridCommand */*notnull*/ instance); +Cp437Grid *sp_cmd_cp437_grid_get(struct Cp437GridCommand */*notnull*/ command); /** - * Reads the origin field of the [`Cp437GridCommand`]. + * Gets the origin field of the [Cp437GridCommand]. * - * This function is part of the sp_cmd_cp437_grid module. + * Rust equivalent: `cp437_command.origin` */ void sp_cmd_cp437_grid_get_origin(struct Cp437GridCommand */*notnull*/ command, size_t */*notnull*/ origin_x, @@ -1710,18 +1677,17 @@ struct Cp437GridCommand */*notnull*/ sp_cmd_cp437_grid_new(Cp437Grid */*notnull* size_t origin_y); /** - * Sets the value of field `grid` of the [`servicepoint::Cp437GridCommand`]. - * The provided value is moved into the instance, potentially invalidating previously taken references. + * Moves the provided bitmap into the provided command. * - * This function is part of the sp_cmd_cp437_grid module. + * This drops the previously contained [Cp437Grid]. */ -void sp_cmd_cp437_grid_set_grid(struct Cp437GridCommand */*notnull*/ instance, - Cp437Grid */*notnull*/ value); +void sp_cmd_cp437_grid_set(struct Cp437GridCommand */*notnull*/ command, + Cp437Grid */*notnull*/ grid); /** - * Overwrites the origin field of the [`Cp437GridCommand`]. + * Sets the origin field of the [Cp437GridCommand]. * - * This function is part of the sp_cmd_cp437_grid module. + * Rust equivalent: `cp437_command.origin = Origin::new(origin_x, origin_y)` */ void sp_cmd_cp437_grid_set_origin(struct Cp437GridCommand */*notnull*/ command, size_t origin_x, @@ -1746,7 +1712,7 @@ void sp_cmd_fade_out_free(struct FadeOutCommand */*notnull*/ instance); /** * A yet-to-be-tested command. * - * Returns: a new [`FadeOutCommand`] instance. + * Returns: a new [FadeOutCommand] instance. * * This function is part of the sp_cmd_fade_out module. */ @@ -1756,8 +1722,6 @@ struct FadeOutCommand */*notnull*/ sp_cmd_fade_out_new(void); * Clones an [SPCommand] instance. * * returns: a new [SPCommand] instance. - * - * This function is part of the sp_cmd_generic module. */ struct Command sp_cmd_generic_clone(struct Command command); @@ -1772,8 +1736,6 @@ struct Command sp_cmd_generic_clone(struct Command command); * SPCommand c = sp_cmd_clear_into_generic(sp_cmd_clear_new()); * sp_command_free(c); * ``` - * - * This function is part of the sp_cmd_generic module. */ void sp_cmd_generic_free(struct Command command); @@ -1782,8 +1744,6 @@ void sp_cmd_generic_free(struct Command command); * The [SPCommand] gets consumed. * * Returns tag [CommandTag::Invalid] in case of an error. - * - * This function is part of the sp_cmd_generic module. */ struct Packet *sp_cmd_generic_into_packet(struct Command command); @@ -1793,8 +1753,6 @@ struct Packet *sp_cmd_generic_into_packet(struct Command command); * The packet is dropped in the process. * * Returns: pointer to new [SPCommand] instance or NULL if parsing failed. - * - * This function is part of the sp_cmd_generic module. */ struct Command sp_cmd_generic_try_from_packet(struct Packet */*notnull*/ packet); @@ -1810,7 +1768,7 @@ void sp_cmd_hard_reset_free(struct HardResetCommand */*notnull*/ instance); * * Please do not send this in your normal program flow. * - * Returns: a new [`HardResetCommand`] instance. + * Returns: a new [HardResetCommand] instance. * * This function is part of the sp_cmd_hard_reset module. */ @@ -1944,14 +1902,6 @@ void sp_cp437_grid_set(Cp437Grid */*notnull*/ instance, */ size_t sp_cp437_grid_width(Cp437Grid */*notnull*/ instance); -/** - * Call this function at the beginning of main to enable rust logging controlled by the - * `RUST_LOG` environment variable. See [env_logger](https://docs.rs/env_logger/latest/env_logger/). - * - * This function is part of the sp_envlogger module. - */ -void sp_envlogger_init(void); - /** *Clones a [`Packet`] instance. * @@ -1970,8 +1920,6 @@ void sp_packet_free(struct Packet */*notnull*/ instance); * Creates a raw [Packet] from parts. * * returns: new instance. Will never return null. - * - * This function is part of the sp_packet module. */ struct Packet */*notnull*/ sp_packet_from_parts(struct Header header, struct ByteSlice payload); @@ -1984,14 +1932,11 @@ struct Packet */*notnull*/ sp_packet_from_parts(struct Header header, struct Header sp_packet_get_header(struct Packet */*notnull*/ instance); /** - * Gets a reference to the field `header` of the [`servicepoint::Packet`]. + * Returns a pointer to the header field of the provided packet. * - * - The returned reference inherits the lifetime of object in which it is contained. - * - The returned pointer may not be used in a function that consumes the instance, e.g. to create a command. - * - * This function is part of the sp_packet module. + * The returned header can be changed and will be valid for the lifetime of the packet. */ -struct Header */*notnull*/ sp_packet_get_header_mut(struct Packet */*notnull*/ instance); +struct Header */*notnull*/ sp_packet_get_header_mut(struct Packet */*notnull*/ packet); /** * Returns a pointer to the current payload of the provided packet. @@ -1999,8 +1944,6 @@ struct Header */*notnull*/ sp_packet_get_header_mut(struct Packet */*notnull*/ i * Returns an [ByteSlice::INVALID] instance in case the packet does not have any payload. * * The returned memory can be changed and will be valid until a new payload is set. - * - * This function is part of the sp_packet module. */ struct ByteSlice sp_packet_get_payload(struct Packet */*notnull*/ packet); @@ -2010,11 +1953,9 @@ struct ByteSlice sp_packet_get_payload(struct Packet */*notnull*/ packet); * # Panics * * - if the buffer is not big enough to hold header+payload. - * - * This function is part of the sp_packet module. */ -size_t sp_packet_serialize_to(struct Packet */*notnull*/ packet, - struct ByteSlice buffer); +void sp_packet_serialize_to(struct Packet */*notnull*/ packet, + struct ByteSlice buffer); /** * Sets the value of field `header` of the [`servicepoint::Packet`]. @@ -2028,8 +1969,6 @@ void sp_packet_set_header(struct Packet */*notnull*/ instance, * Sets the payload of the provided packet to the provided data. * * This makes previous payload pointers invalid. - * - * This function is part of the sp_packet module. */ void sp_packet_set_payload(struct Packet */*notnull*/ packet, struct ByteSlice data); @@ -2038,8 +1977,6 @@ void sp_packet_set_payload(struct Packet */*notnull*/ packet, * Tries to load a [Packet] from the passed array with the specified length. * * returns: NULL in case of an error, pointer to the allocated packet otherwise - * - * This function is part of the sp_packet module. */ struct Packet *sp_packet_try_load(struct ByteSlice data); @@ -2047,8 +1984,6 @@ struct Packet *sp_packet_try_load(struct ByteSlice data); * Converts u16 into [CommandCode]. * * If the provided value is not valid, false is returned and result is not changed. - * - * This function is part of the sp module. */ bool sp_u16_to_command_code(uint16_t code, CommandCode *result); @@ -2072,8 +2007,6 @@ void sp_udp_free(struct UdpSocket */*notnull*/ instance); * if (connection != NULL) * sp_udp_send_command(connection, sp_command_clear()); * ``` - * - * This function is part of the sp_udp module. */ struct UdpSocket *sp_udp_open(char */*notnull*/ host); @@ -2089,8 +2022,6 @@ struct UdpSocket *sp_udp_open(char */*notnull*/ host); * if (connection != NULL) * sp_udp_send_command(connection, sp_command_clear()); * ``` - * - * This function is part of the sp_udp module. */ struct UdpSocket *sp_udp_open_ipv4(uint8_t ip1, uint8_t ip2, @@ -2110,8 +2041,6 @@ struct UdpSocket *sp_udp_open_ipv4(uint8_t ip1, * ```C * sp_udp_send_command(connection, sp_command_brightness(5)); * ``` - * - * This function is part of the sp_udp module. */ bool sp_udp_send_command(struct UdpSocket */*notnull*/ connection, struct Command command); @@ -2126,8 +2055,6 @@ bool sp_udp_send_command(struct UdpSocket */*notnull*/ connection, * ```C * sp_udp_send_header(connection, sp_command_brightness(5)); * ``` - * - * This function is part of the sp_udp module. */ bool sp_udp_send_header(struct UdpSocket */*notnull*/ udp_connection, struct Header header); @@ -2138,8 +2065,6 @@ bool sp_udp_send_header(struct UdpSocket */*notnull*/ udp_connection, * The passed `packet` gets consumed. * * returns: true in case of success - * - * This function is part of the sp_udp module. */ bool sp_udp_send_packet(struct UdpSocket */*notnull*/ connection, struct Packet */*notnull*/ packet); diff --git a/src/commands/bitmap_command.rs b/src/commands/bitmap_command.rs index 68f6408..f4c9a7e 100644 --- a/src/commands/bitmap_command.rs +++ b/src/commands/bitmap_command.rs @@ -1,22 +1,12 @@ use crate::{ - commands::wrap_origin_accessors, macros::{wrap_clone, wrap_fields, wrap_free, wrap_functions}, mem::{heap_move_nonnull, heap_move_ok, heap_remove}, }; use servicepoint::{Bitmap, BitmapCommand, CompressionCode, Origin, Packet}; use std::ptr::NonNull; -wrap_clone!(sp_cmd_bitmap::BitmapCommand); -wrap_free!(sp_cmd_bitmap::BitmapCommand); - -wrap_fields!(sp_cmd_bitmap::BitmapCommand; - prop bitmap: Bitmap { mut get(); move set(value); }; - prop compression: CompressionCode { get(); set(value); }; -); - -wrap_origin_accessors!(sp_cmd_bitmap::BitmapCommand); - wrap_functions!(sp_cmd_bitmap; + /// Sets a window of pixels to the specified values. /// /// The passed [Bitmap] gets consumed. @@ -53,4 +43,74 @@ wrap_functions!(sp_cmd_bitmap; ) -> *mut Packet { heap_move_ok(unsafe { heap_remove(command) }.try_into()) } + ); + +wrap_clone!(sp_cmd_bitmap::BitmapCommand); +wrap_free!(sp_cmd_bitmap::BitmapCommand); + +wrap_fields!( + sp_cmd_bitmap::BitmapCommand; + //prop bitmap: NonNull { + // get() { + // return NonNull::from(bitmap); + // }; + // set(value) { + // return unsafe { heap_remove(value) }; + // }; + //}; + prop compression: CompressionCode { + get(); + set(value); + }; +); + +/// Returns a pointer to the provided `BitmapCommand`. +/// +/// # Safety +/// +/// - The returned bitmap inherits the lifetime of the command in which it is contained. +/// - The returned pointer may not be used in a function that consumes the instance, e.g. to create a command. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_bitmap_get( + mut command: NonNull, +) -> NonNull { + unsafe { NonNull::from(&mut (command.as_mut().bitmap)) } +} + +/// Moves the provided [Bitmap] to be contained in the [BitmapCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_bitmap_set( + mut command: NonNull, + bitmap: NonNull, +) { + unsafe { + command.as_mut().bitmap = heap_remove(bitmap); + } +} + +/// Reads the origin field of the [BitmapCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_bitmap_get_origin( + command: NonNull, + origin_x: NonNull, + origin_y: NonNull, +) { + unsafe { + let origin = &command.as_ref().origin; + *origin_x.as_ptr() = origin.x; + *origin_y.as_ptr() = origin.y; + } +} + +/// Overwrites the origin field of the [BitmapCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_bitmap_set_origin( + mut command: NonNull, + origin_x: usize, + origin_y: usize, +) { + unsafe { + command.as_mut().origin = Origin::new(origin_x, origin_y); + } +} diff --git a/src/commands/bitvec_command.rs b/src/commands/bitvec_command.rs index 6cec313..7dfed38 100644 --- a/src/commands/bitvec_command.rs +++ b/src/commands/bitvec_command.rs @@ -8,16 +8,6 @@ use servicepoint::{ }; use std::ptr::NonNull; -wrap_clone!(sp_cmd_bitvec::BitVecCommand); -wrap_free!(sp_cmd_bitvec::BitVecCommand); - -wrap_fields!(sp_cmd_bitvec::BitVecCommand; - prop bitvec: DisplayBitVec { mut get(); move set(value); }; - prop offset: Offset { get(); set(value); }; - prop operation: BinaryOperation { get(); set(value); }; - prop compression: CompressionCode { get(); set(value); }; -); - wrap_functions!(sp_cmd_bitvec; /// Set pixel data starting at the pixel offset on screen. @@ -56,3 +46,41 @@ wrap_functions!(sp_cmd_bitvec; } ); + +wrap_clone!(sp_cmd_bitvec::BitVecCommand); +wrap_free!(sp_cmd_bitvec::BitVecCommand); + +wrap_fields!( + sp_cmd_bitvec::BitVecCommand; + prop offset: Offset { + get(); + set(value); + }; + prop operation: BinaryOperation { + get(); + set(value); + }; + prop compression: CompressionCode { + get(); + set(value); + }; +); + +/// Returns a pointer to the [BitVec] contained in the [BitVecCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_bitvec_get( + mut command: NonNull, +) -> *mut DisplayBitVec { + unsafe { &mut command.as_mut().bitvec } +} + +/// Moves the provided [BitVec] to be contained in the [BitVecCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_bitvec_set( + mut command: NonNull, + bitvec: NonNull, +) { + unsafe { + command.as_mut().bitvec = heap_remove(bitvec); + } +} diff --git a/src/commands/brightness_grid_command.rs b/src/commands/brightness_grid_command.rs index cc26b77..b4e6e23 100644 --- a/src/commands/brightness_grid_command.rs +++ b/src/commands/brightness_grid_command.rs @@ -1,20 +1,10 @@ use crate::{ - commands::wrap_origin_accessors, - macros::{wrap_clone, wrap_fields, wrap_free, wrap_functions}, + macros::{wrap_clone, wrap_free, wrap_functions}, mem::{heap_move_nonnull, heap_move_ok, heap_remove}, }; use servicepoint::{BrightnessGrid, BrightnessGridCommand, Origin, Packet}; use std::ptr::NonNull; -wrap_clone!(sp_cmd_brightness_grid::BrightnessGridCommand); -wrap_free!(sp_cmd_brightness_grid::BrightnessGridCommand); - -wrap_fields!(sp_cmd_brightness_grid::BrightnessGridCommand; - prop grid: BrightnessGrid { mut get(); move set(grid); }; -); - -wrap_origin_accessors!(sp_cmd_brightness_grid::BrightnessGridCommand); - wrap_functions!(sp_cmd_brightness_grid; /// Set the brightness of individual tiles in a rectangular area of the display. @@ -51,3 +41,51 @@ wrap_functions!(sp_cmd_brightness_grid; } ); + +wrap_clone!(sp_cmd_brightness_grid::BrightnessGridCommand); +wrap_free!(sp_cmd_brightness_grid::BrightnessGridCommand); + +/// Moves the provided [BrightnessGrid] to be contained in the [BrightnessGridCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_brightness_grid_set( + mut command: NonNull, + grid: NonNull, +) { + unsafe { + command.as_mut().grid = heap_remove(grid); + } +} + +/// Returns a pointer to the [BrightnessGrid] contained in the [BrightnessGridCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_brightness_grid_get( + mut command: NonNull, +) -> *mut BrightnessGrid { + unsafe { &mut command.as_mut().grid } +} + +/// Overwrites the origin field of the [BrightnessGridCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_brightness_grid_get_origin( + command: NonNull, + origin_x: NonNull, + origin_y: NonNull, +) { + unsafe { + let origin = &command.as_ref().origin; + *origin_x.as_ptr() = origin.x; + *origin_y.as_ptr() = origin.y; + } +} + +/// Reads the origin field of the [BrightnessGridCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_brightness_grid_set_origin( + mut command: NonNull, + origin_x: usize, + origin_y: usize, +) { + unsafe { + command.as_mut().origin = Origin::new(origin_x, origin_y); + } +} diff --git a/src/commands/cc_only_commands.rs b/src/commands/cc_only_commands.rs index f4162a0..234b781 100644 --- a/src/commands/cc_only_commands.rs +++ b/src/commands/cc_only_commands.rs @@ -5,33 +5,39 @@ use crate::{ use servicepoint::{ClearCommand, FadeOutCommand, HardResetCommand}; use std::ptr::NonNull; -macro_rules! wrap_cc_only { - ($prefix:ident :: $typ:ident ; $(#[$meta:meta])*) => { - wrap_functions!($prefix; - $(#[$meta])* - /// - #[doc = concat!(" Returns: a new [`",stringify!($typ),"`] instance.")] - fn new() -> NonNull<$typ> { - heap_move_nonnull($typ) - } - ); - - wrap_free!($prefix :: $typ); - }; -} - -wrap_cc_only!(sp_cmd_clear::ClearCommand; +wrap_functions!(sp_cmd_clear; /// Set all pixels to the off state. /// /// Does not affect brightness. + /// + /// Returns: a new [ClearCommand] instance. + fn new() -> NonNull { + heap_move_nonnull(ClearCommand) + } ); -wrap_cc_only!(sp_cmd_hard_reset::HardResetCommand; +wrap_free!(sp_cmd_clear::ClearCommand); + +wrap_functions!(sp_cmd_hard_reset; /// Kills the udp daemon on the display, which usually results in a restart. /// /// Please do not send this in your normal program flow. + /// + /// Returns: a new [HardResetCommand] instance. + fn new() -> NonNull { + heap_move_nonnull(HardResetCommand) + } ); -wrap_cc_only!(sp_cmd_fade_out::FadeOutCommand; +wrap_free!(sp_cmd_hard_reset::HardResetCommand); + +wrap_functions!(sp_cmd_fade_out; /// A yet-to-be-tested command. + /// + /// Returns: a new [FadeOutCommand] instance. + fn new() -> NonNull { + heap_move_nonnull(FadeOutCommand) + } ); + +wrap_free!(sp_cmd_fade_out::FadeOutCommand); diff --git a/src/commands/char_grid_command.rs b/src/commands/char_grid_command.rs index fe97dc0..0ef90c0 100644 --- a/src/commands/char_grid_command.rs +++ b/src/commands/char_grid_command.rs @@ -1,20 +1,10 @@ use crate::{ - commands::wrap_origin_accessors, - macros::{wrap_clone, wrap_fields, wrap_free, wrap_functions}, + macros::{wrap_clone, wrap_free, wrap_functions}, mem::{heap_move_nonnull, heap_move_ok, heap_remove}, }; use servicepoint::{CharGrid, CharGridCommand, Origin, Packet}; use std::ptr::NonNull; -wrap_clone!(sp_cmd_char_grid::CharGridCommand); -wrap_free!(sp_cmd_char_grid::CharGridCommand); - -wrap_fields!(sp_cmd_char_grid::CharGridCommand; - prop grid: CharGrid { mut get(); move set(grid); }; -); - -wrap_origin_accessors!(sp_cmd_char_grid::CharGridCommand); - wrap_functions!(sp_cmd_char_grid; /// Show UTF-8 encoded text on the screen. @@ -51,3 +41,51 @@ wrap_functions!(sp_cmd_char_grid; } ); + +wrap_clone!(sp_cmd_char_grid::CharGridCommand); +wrap_free!(sp_cmd_char_grid::CharGridCommand); + +/// Moves the provided [CharGrid] to be contained in the [CharGridCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_char_grid_set( + mut command: NonNull, + grid: NonNull, +) { + unsafe { + command.as_mut().grid = heap_remove(grid); + } +} + +/// Returns a pointer to the [CharGrid] contained in the [CharGridCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_char_grid_get( + mut command: NonNull, +) -> NonNull { + unsafe { NonNull::from(&mut command.as_mut().grid) } +} + +/// Reads the origin field of the [CharGridCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_char_grid_get_origin( + command: NonNull, + origin_x: NonNull, + origin_y: NonNull, +) { + unsafe { + let origin = &command.as_ref().origin; + *origin_x.as_ptr() = origin.x; + *origin_y.as_ptr() = origin.y; + } +} + +/// Overwrites the origin field of the [CharGridCommand]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_char_grid_set_origin( + mut command: NonNull, + origin_x: usize, + origin_y: usize, +) { + unsafe { + command.as_mut().origin = Origin::new(origin_x, origin_y); + } +} diff --git a/src/commands/cp437_grid_command.rs b/src/commands/cp437_grid_command.rs index 25294bb..da8380a 100644 --- a/src/commands/cp437_grid_command.rs +++ b/src/commands/cp437_grid_command.rs @@ -1,20 +1,10 @@ use crate::{ - commands::wrap_origin_accessors, - macros::{wrap_clone, wrap_fields, wrap_free, wrap_functions}, + macros::{wrap_clone, wrap_free, wrap_functions}, mem::{heap_move_nonnull, heap_move_ok, heap_remove}, }; use servicepoint::{Cp437Grid, Cp437GridCommand, Origin, Packet}; use std::ptr::NonNull; -wrap_clone!(sp_cmd_cp437_grid::Cp437GridCommand); -wrap_free!(sp_cmd_cp437_grid::Cp437GridCommand); - -wrap_fields!(sp_cmd_cp437_grid::Cp437GridCommand; - prop grid: Cp437Grid { mut get(); move set(grid); }; -); - -wrap_origin_accessors!(sp_cmd_cp437_grid::Cp437GridCommand); - wrap_functions!(sp_cmd_cp437_grid; /// Show text on the screen. @@ -51,3 +41,62 @@ wrap_functions!(sp_cmd_cp437_grid; } ); + +wrap_clone!(sp_cmd_cp437_grid::Cp437GridCommand); +wrap_free!(sp_cmd_cp437_grid::Cp437GridCommand); + +/// Moves the provided bitmap into the provided command. +/// +/// This drops the previously contained [Cp437Grid]. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_cp437_grid_set( + mut command: NonNull, + grid: NonNull, +) { + unsafe { + command.as_mut().grid = heap_remove(grid); + } +} + +/// Show text on the screen. +/// +/// The text is sent in the form of a 2D grid of [CP-437] encoded characters. +/// For sending UTF-8 encoded characters, see [servicepoint::CharGridCommand]. +/// +/// [CP-437]: https://en.wikipedia.org/wiki/Code_page_437 +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_cp437_grid_get( + mut command: NonNull, +) -> *mut Cp437Grid { + unsafe { &mut command.as_mut().grid } +} + +/// Gets the origin field of the [Cp437GridCommand]. +/// +/// Rust equivalent: `cp437_command.origin` +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_cp437_grid_get_origin( + command: NonNull, + origin_x: NonNull, + origin_y: NonNull, +) { + unsafe { + let origin = &command.as_ref().origin; + *origin_x.as_ptr() = origin.x; + *origin_y.as_ptr() = origin.y; + } +} + +/// Sets the origin field of the [Cp437GridCommand]. +/// +/// Rust equivalent: `cp437_command.origin = Origin::new(origin_x, origin_y)` +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_cp437_grid_set_origin( + mut command: NonNull, + origin_x: usize, + origin_y: usize, +) { + unsafe { + command.as_mut().origin = Origin::new(origin_x, origin_y); + } +} diff --git a/src/commands/generic_command.rs b/src/commands/generic_command.rs index 9734d30..840900f 100644 --- a/src/commands/generic_command.rs +++ b/src/commands/generic_command.rs @@ -1,9 +1,6 @@ -use crate::{ - macros::wrap_functions, - mem::{ - heap_clone, heap_drop, heap_move, heap_move_nonnull, heap_move_ok, - heap_remove, - }, +use crate::mem::{ + heap_clone, heap_drop, heap_move, heap_move_nonnull, heap_move_ok, + heap_remove, }; use servicepoint::{ BitVecCommand, BitmapCommand, BrightnessGridCommand, CharGridCommand, @@ -69,233 +66,233 @@ impl SPCommand { }; } -wrap_functions!(sp_cmd_generic; +/// Tries to turn a [Packet] into a [SPCommand]. +/// +/// The packet is dropped in the process. +/// +/// Returns: pointer to new [SPCommand] instance or NULL if parsing failed. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_generic_try_from_packet( + packet: NonNull, +) -> SPCommand { + let packet = *unsafe { Box::from_raw(packet.as_ptr()) }; + servicepoint::TypedCommand::try_from(packet) + .map(|value| match value { + TypedCommand::Clear(clear) => SPCommand { + tag: CommandTag::Clear, + data: CommandUnion { + clear: heap_move_nonnull(clear), + }, + }, + TypedCommand::CharGrid(char_grid) => SPCommand { + tag: CommandTag::CharGrid, + data: CommandUnion { + char_grid: heap_move_nonnull(char_grid), + }, + }, + TypedCommand::Cp437Grid(cp437_grid) => SPCommand { + tag: CommandTag::Cp437Grid, + data: CommandUnion { + cp437_grid: heap_move_nonnull(cp437_grid), + }, + }, + TypedCommand::Bitmap(bitmap) => SPCommand { + tag: CommandTag::Bitmap, + data: CommandUnion { + bitmap: heap_move_nonnull(bitmap), + }, + }, + TypedCommand::Brightness(global_brightness) => SPCommand { + tag: CommandTag::GlobalBrightness, + data: CommandUnion { + global_brightness: heap_move_nonnull(global_brightness), + }, + }, + TypedCommand::BrightnessGrid(brightness_grid) => SPCommand { + tag: CommandTag::BrightnessGrid, + data: CommandUnion { + brightness_grid: heap_move_nonnull(brightness_grid), + }, + }, + TypedCommand::BitVec(bitvec) => SPCommand { + tag: CommandTag::BitVec, + data: CommandUnion { + bitvec: heap_move_nonnull(bitvec), + }, + }, + TypedCommand::HardReset(hard_reset) => SPCommand { + tag: CommandTag::HardReset, + data: CommandUnion { + hard_reset: heap_move_nonnull(hard_reset), + }, + }, + TypedCommand::FadeOut(fade_out) => SPCommand { + tag: CommandTag::FadeOut, + data: CommandUnion { + fade_out: heap_move_nonnull(fade_out), + }, + }, + #[allow(deprecated)] + TypedCommand::BitmapLegacy(bitmap_legacy) => SPCommand { + tag: CommandTag::BitmapLegacy, + data: CommandUnion { + bitmap_legacy: heap_move_nonnull(bitmap_legacy), + }, + }, + }) + .unwrap_or_else(move |_| SPCommand { + tag: CommandTag::Invalid, + data: CommandUnion { null: null_mut() }, + }) +} - /// Tries to turn a [Packet] into a [SPCommand]. - /// - /// The packet is dropped in the process. - /// - /// Returns: pointer to new [SPCommand] instance or NULL if parsing failed. - fn try_from_packet( - packet: NonNull, - ) -> SPCommand { - let packet = *unsafe { Box::from_raw(packet.as_ptr()) }; - servicepoint::TypedCommand::try_from(packet) - .map(|value| match value { - TypedCommand::Clear(clear) => SPCommand { - tag: CommandTag::Clear, - data: CommandUnion { - clear: heap_move_nonnull(clear), - }, - }, - TypedCommand::CharGrid(char_grid) => SPCommand { - tag: CommandTag::CharGrid, - data: CommandUnion { - char_grid: heap_move_nonnull(char_grid), - }, - }, - TypedCommand::Cp437Grid(cp437_grid) => SPCommand { - tag: CommandTag::Cp437Grid, - data: CommandUnion { - cp437_grid: heap_move_nonnull(cp437_grid), - }, - }, - TypedCommand::Bitmap(bitmap) => SPCommand { - tag: CommandTag::Bitmap, - data: CommandUnion { - bitmap: heap_move_nonnull(bitmap), - }, - }, - TypedCommand::Brightness(global_brightness) => SPCommand { - tag: CommandTag::GlobalBrightness, - data: CommandUnion { - global_brightness: heap_move_nonnull(global_brightness), - }, - }, - TypedCommand::BrightnessGrid(brightness_grid) => SPCommand { - tag: CommandTag::BrightnessGrid, - data: CommandUnion { - brightness_grid: heap_move_nonnull(brightness_grid), - }, - }, - TypedCommand::BitVec(bitvec) => SPCommand { - tag: CommandTag::BitVec, - data: CommandUnion { - bitvec: heap_move_nonnull(bitvec), - }, - }, - TypedCommand::HardReset(hard_reset) => SPCommand { - tag: CommandTag::HardReset, - data: CommandUnion { - hard_reset: heap_move_nonnull(hard_reset), - }, - }, - TypedCommand::FadeOut(fade_out) => SPCommand { - tag: CommandTag::FadeOut, - data: CommandUnion { - fade_out: heap_move_nonnull(fade_out), - }, - }, - #[allow(deprecated)] - TypedCommand::BitmapLegacy(bitmap_legacy) => SPCommand { - tag: CommandTag::BitmapLegacy, - data: CommandUnion { - bitmap_legacy: heap_move_nonnull(bitmap_legacy), - }, - }, - }) - .unwrap_or_else(move |_| SPCommand { - tag: CommandTag::Invalid, - data: CommandUnion { null: null_mut() }, - }) - } - - /// Clones an [SPCommand] instance. - /// - /// returns: a new [SPCommand] instance. - fn clone(command: SPCommand) -> SPCommand { - unsafe { - match command.tag { - CommandTag::Clear => SPCommand { - tag: CommandTag::Clear, - data: CommandUnion { - clear: heap_clone(command.data.clear), - }, - }, - CommandTag::CharGrid => SPCommand { - tag: CommandTag::CharGrid, - data: CommandUnion { - char_grid: heap_clone(command.data.char_grid), - }, - }, - CommandTag::Cp437Grid => SPCommand { - tag: CommandTag::Cp437Grid, - data: CommandUnion { - cp437_grid: heap_clone(command.data.cp437_grid), - }, - }, - CommandTag::Bitmap => SPCommand { - tag: CommandTag::Bitmap, - data: CommandUnion { - bitmap: heap_clone(command.data.bitmap), - }, - }, - CommandTag::GlobalBrightness => SPCommand { - tag: CommandTag::GlobalBrightness, - data: CommandUnion { - global_brightness: heap_clone( - command.data.global_brightness, - ), - }, - }, - CommandTag::BrightnessGrid => SPCommand { - tag: CommandTag::BrightnessGrid, - data: CommandUnion { - brightness_grid: heap_clone(command.data.brightness_grid), - }, - }, - CommandTag::BitVec => SPCommand { - tag: CommandTag::BitVec, - data: CommandUnion { - bitvec: heap_clone(command.data.bitvec), - }, - }, - CommandTag::HardReset => SPCommand { - tag: CommandTag::HardReset, - data: CommandUnion { - hard_reset: heap_clone(command.data.hard_reset), - }, - }, - CommandTag::FadeOut => SPCommand { - tag: CommandTag::FadeOut, - data: CommandUnion { - fade_out: heap_clone(command.data.fade_out), - }, - }, - #[allow(deprecated)] - CommandTag::BitmapLegacy => SPCommand { - tag: CommandTag::BitmapLegacy, - data: CommandUnion { - bitmap_legacy: heap_clone(command.data.bitmap_legacy), - }, - }, - CommandTag::Invalid => SPCommand::INVALID, - } - } - } - - /// Deallocates an [SPCommand]. - /// - /// Commands with an invalid `tag` do not have to be freed as the `data` pointer should be null. - /// - /// # Examples - /// - /// ```C - /// SPCommand c = sp_cmd_clear_into_generic(sp_cmd_clear_new()); - /// sp_command_free(c); - /// ``` - fn free(command: SPCommand) { - unsafe { - match command.tag { - CommandTag::Invalid => (), - CommandTag::Bitmap => heap_drop(command.data.bitmap), - CommandTag::BitVec => heap_drop(command.data.bitvec), - CommandTag::BrightnessGrid => { - heap_drop(command.data.brightness_grid) - } - CommandTag::CharGrid => heap_drop(command.data.char_grid), - CommandTag::Cp437Grid => heap_drop(command.data.cp437_grid), - CommandTag::GlobalBrightness => { - heap_drop(command.data.global_brightness) - } - CommandTag::Clear => heap_drop(command.data.clear), - CommandTag::HardReset => heap_drop(command.data.hard_reset), - CommandTag::FadeOut => heap_drop(command.data.fade_out), - CommandTag::BitmapLegacy => heap_drop(command.data.bitmap_legacy), - } - } - } - - /// Tries to turn a [SPCommand] into a [Packet]. - /// The [SPCommand] gets consumed. - /// - /// Returns tag [CommandTag::Invalid] in case of an error. - fn into_packet( - command: SPCommand, - ) -> *mut Packet { +/// Clones an [SPCommand] instance. +/// +/// returns: a new [SPCommand] instance. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_generic_clone(command: SPCommand) -> SPCommand { + unsafe { match command.tag { - CommandTag::Invalid => null_mut(), - CommandTag::Bitmap => { - heap_move_ok(unsafe { heap_remove(command.data.bitmap).try_into() }) - } - CommandTag::BitVec => { - heap_move_ok(unsafe { heap_remove(command.data.bitvec).try_into() }) - } - CommandTag::BrightnessGrid => heap_move_ok(unsafe { - heap_remove(command.data.brightness_grid).try_into() - }), - CommandTag::CharGrid => heap_move_ok(unsafe { - heap_remove(command.data.char_grid).try_into() - }), - CommandTag::Cp437Grid => heap_move_ok(unsafe { - heap_remove(command.data.cp437_grid).try_into() - }), - CommandTag::GlobalBrightness => heap_move(unsafe { - heap_remove(command.data.global_brightness).into() - }), - CommandTag::Clear => { - heap_move(unsafe { heap_remove(command.data.clear).into() }) - } - CommandTag::HardReset => { - heap_move(unsafe { heap_remove(command.data.hard_reset).into() }) - } - CommandTag::FadeOut => { - heap_move(unsafe { heap_remove(command.data.fade_out).into() }) - } - CommandTag::BitmapLegacy => { - heap_move(unsafe { heap_remove(command.data.bitmap_legacy).into() }) - } + CommandTag::Clear => SPCommand { + tag: CommandTag::Clear, + data: CommandUnion { + clear: heap_clone(command.data.clear), + }, + }, + CommandTag::CharGrid => SPCommand { + tag: CommandTag::CharGrid, + data: CommandUnion { + char_grid: heap_clone(command.data.char_grid), + }, + }, + CommandTag::Cp437Grid => SPCommand { + tag: CommandTag::Cp437Grid, + data: CommandUnion { + cp437_grid: heap_clone(command.data.cp437_grid), + }, + }, + CommandTag::Bitmap => SPCommand { + tag: CommandTag::Bitmap, + data: CommandUnion { + bitmap: heap_clone(command.data.bitmap), + }, + }, + CommandTag::GlobalBrightness => SPCommand { + tag: CommandTag::GlobalBrightness, + data: CommandUnion { + global_brightness: heap_clone( + command.data.global_brightness, + ), + }, + }, + CommandTag::BrightnessGrid => SPCommand { + tag: CommandTag::BrightnessGrid, + data: CommandUnion { + brightness_grid: heap_clone(command.data.brightness_grid), + }, + }, + CommandTag::BitVec => SPCommand { + tag: CommandTag::BitVec, + data: CommandUnion { + bitvec: heap_clone(command.data.bitvec), + }, + }, + CommandTag::HardReset => SPCommand { + tag: CommandTag::HardReset, + data: CommandUnion { + hard_reset: heap_clone(command.data.hard_reset), + }, + }, + CommandTag::FadeOut => SPCommand { + tag: CommandTag::FadeOut, + data: CommandUnion { + fade_out: heap_clone(command.data.fade_out), + }, + }, + #[allow(deprecated)] + CommandTag::BitmapLegacy => SPCommand { + tag: CommandTag::BitmapLegacy, + data: CommandUnion { + bitmap_legacy: heap_clone(command.data.bitmap_legacy), + }, + }, + CommandTag::Invalid => SPCommand::INVALID, } } +} -); +/// Deallocates an [SPCommand]. +/// +/// Commands with an invalid `tag` do not have to be freed as the `data` pointer should be null. +/// +/// # Examples +/// +/// ```C +/// SPCommand c = sp_cmd_clear_into_generic(sp_cmd_clear_new()); +/// sp_command_free(c); +/// ``` +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_generic_free(command: SPCommand) { + unsafe { + match command.tag { + CommandTag::Invalid => (), + CommandTag::Bitmap => heap_drop(command.data.bitmap), + CommandTag::BitVec => heap_drop(command.data.bitvec), + CommandTag::BrightnessGrid => { + heap_drop(command.data.brightness_grid) + } + CommandTag::CharGrid => heap_drop(command.data.char_grid), + CommandTag::Cp437Grid => heap_drop(command.data.cp437_grid), + CommandTag::GlobalBrightness => { + heap_drop(command.data.global_brightness) + } + CommandTag::Clear => heap_drop(command.data.clear), + CommandTag::HardReset => heap_drop(command.data.hard_reset), + CommandTag::FadeOut => heap_drop(command.data.fade_out), + CommandTag::BitmapLegacy => heap_drop(command.data.bitmap_legacy), + } + } +} + +/// Tries to turn a [SPCommand] into a [Packet]. +/// The [SPCommand] gets consumed. +/// +/// Returns tag [CommandTag::Invalid] in case of an error. +#[no_mangle] +pub unsafe extern "C" fn sp_cmd_generic_into_packet( + command: SPCommand, +) -> *mut Packet { + match command.tag { + CommandTag::Invalid => null_mut(), + CommandTag::Bitmap => { + heap_move_ok(unsafe { heap_remove(command.data.bitmap).try_into() }) + } + CommandTag::BitVec => { + heap_move_ok(unsafe { heap_remove(command.data.bitvec).try_into() }) + } + CommandTag::BrightnessGrid => heap_move_ok(unsafe { + heap_remove(command.data.brightness_grid).try_into() + }), + CommandTag::CharGrid => heap_move_ok(unsafe { + heap_remove(command.data.char_grid).try_into() + }), + CommandTag::Cp437Grid => heap_move_ok(unsafe { + heap_remove(command.data.cp437_grid).try_into() + }), + CommandTag::GlobalBrightness => heap_move(unsafe { + heap_remove(command.data.global_brightness).into() + }), + CommandTag::Clear => { + heap_move(unsafe { heap_remove(command.data.clear).into() }) + } + CommandTag::HardReset => { + heap_move(unsafe { heap_remove(command.data.hard_reset).into() }) + } + CommandTag::FadeOut => { + heap_move(unsafe { heap_remove(command.data.fade_out).into() }) + } + CommandTag::BitmapLegacy => { + heap_move(unsafe { heap_remove(command.data.bitmap_legacy).into() }) + } + } +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index a6fa74d..3cbb99a 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -13,35 +13,3 @@ pub use brightness_grid_command::*; pub use char_grid_command::*; pub use cp437_grid_command::*; pub use generic_command::*; - -macro_rules! wrap_origin_accessors { - ( $prefix:ident :: $object_type:ty ) => { - $crate::macros::wrap_functions!($prefix; - #[doc = concat!(" Reads the origin field of the [`", stringify!($object_type), "`].")] - fn get_origin( - command: NonNull<$object_type>, - origin_x: NonNull, - origin_y: NonNull, - ) { - unsafe { - let origin = &command.as_ref().origin; - *origin_x.as_ptr() = origin.x; - *origin_y.as_ptr() = origin.y; - } - } - - #[doc = concat!(" Overwrites the origin field of the [`", stringify!($object_type), "`].")] - fn set_origin( - command: NonNull<$object_type>, - origin_x: usize, - origin_y: usize, - ) { - unsafe { - $crate::macros::nonnull_as_mut!(command).origin = ::servicepoint::Origin::new(origin_x, origin_y); - } - } - ); - }; -} - -pub(crate) use wrap_origin_accessors; diff --git a/src/containers/byte_slice.rs b/src/containers/byte_slice.rs index 10ee22f..0642cfc 100644 --- a/src/containers/byte_slice.rs +++ b/src/containers/byte_slice.rs @@ -35,7 +35,7 @@ impl ByteSlice { unsafe { std::slice::from_raw_parts(self.start, self.length) } } - pub(crate) unsafe fn as_slice_mut(&self) -> &mut [u8] { + pub(crate) unsafe fn as_slice_mut(&mut self) -> &mut [u8] { unsafe { std::slice::from_raw_parts_mut(self.start, self.length) } } diff --git a/src/lib.rs b/src/lib.rs index 344a1a2..e08fbd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,13 +47,10 @@ pub struct DisplayBitVec; #[cfg(feature = "env_logger")] mod feature_env_logger { - use crate::macros::wrap_functions; - - wrap_functions!(sp_envlogger; - /// Call this function at the beginning of main to enable rust logging controlled by the - /// `RUST_LOG` environment variable. See [env_logger](https://docs.rs/env_logger/latest/env_logger/). - fn init() { - env_logger::init(); - } - ); + /// Call this function at the beginning of main to enable rust logging controlled by the + /// `RUST_LOG` environment variable. See [env_logger](https://docs.rs/env_logger/latest/env_logger/). + #[no_mangle] + pub unsafe extern "C" fn init_env_logger() { + env_logger::init(); + } } diff --git a/src/macros.rs b/src/macros.rs index 4157f28..8d4ba47 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -28,7 +28,7 @@ macro_rules! nonnull_as_ref { macro_rules! nonnull_as_mut { ($ident:ident) => { - (&mut *$ident.as_ptr()) + &mut *$ident.as_ptr() }; } @@ -84,37 +84,21 @@ macro_rules! wrap_fields { ( $prefix:ident :: $object_type:ty; $( - prop $prop_name:ident : $prop_type:ty { - $( - get() $({ - $(#[$get_meta:meta])* - $(return $get_expr:expr;)? - })?; - )? - - $( - mut get() $({ - $(#[$get_mut_meta:meta])* - $(return $get_mut_expr:expr;)? - })?; - )? - - $( - set($value:ident) - $({ - $(#[$set_meta:meta])* - $(return $set_expr:expr;)? - })?; - )? - - $( - move set( $set_move_value:ident) - $({ - $(#[$set_move_meta:meta])* - $(return $set_move_expr:expr;)? - })?; - )? - }; + prop $prop_name:ident : $prop_type:ty { + $( + get() $({ + $(#[$get_meta:meta])* + $(return $get_expr:expr;)? + })?; + )? + $( + set($value:ident) + $({ + $(#[$set_meta:meta])* + $(return $set_expr:expr;)? + })?; + )? + }; )+ ) => { paste::paste! { @@ -122,15 +106,16 @@ macro_rules! wrap_fields { $( $( #[doc = concat!(" Gets the value of field `", stringify!($prop_name), - "` of the [`servicepoint::", stringify!($object_type),"`].")] + "` of the [`servicepoint::",stringify!($object_type),"`].")] $($( #[doc = ""] #[$get_meta] )*)? fn []( - instance: ::core::ptr::NonNull<$object_type> + instance: NonNull<$object_type> ) -> $prop_type { - let $prop_name = unsafe { $crate::macros::nonnull_as_ref!(instance).$prop_name }; + let instance = unsafe { $crate::macros::nonnull_as_ref!(instance) }; + let $prop_name = instance.$prop_name; $($( let $prop_name = $get_expr; )?)? @@ -138,27 +123,6 @@ macro_rules! wrap_fields { } )? - $( - #[doc = concat!(" Gets a reference to the field `", stringify!($prop_name), - "` of the [`servicepoint::",stringify!($object_type),"`].")] - $($( - #[doc = ""] - #[$get_mut_meta] - )*)? - #[doc = ""] - #[doc = " - The returned reference inherits the lifetime of object in which it is contained."] - #[doc = " - The returned pointer may not be used in a function that consumes the instance, e.g. to create a command."] - fn []( - instance: ::core::ptr::NonNull<$object_type> - ) -> ::core::ptr::NonNull<$prop_type> { - let $prop_name = unsafe { &mut $crate::macros::nonnull_as_mut!(instance).$prop_name }; - $($( - let $prop_name = $get_mut_expr; - )?)? - return ::core::ptr::NonNull::from($prop_name); - } - )? - $( #[doc = concat!(" Sets the value of field `", stringify!($prop_name), "` of the [`servicepoint::",stringify!($object_type),"`].")] @@ -167,7 +131,7 @@ macro_rules! wrap_fields { #[$set_meta] )*)? fn []( - instance: ::core::ptr::NonNull<$object_type>, + instance: NonNull<$object_type>, value: $prop_type, ) { let instance = unsafe { $crate::macros::nonnull_as_mut!(instance) }; @@ -178,29 +142,6 @@ macro_rules! wrap_fields { instance.$prop_name = value; } )? - - $( - #[doc = concat!(" Sets the value of field `", stringify!($prop_name), - "` of the [`servicepoint::",stringify!($object_type),"`].")] - #[doc = concat!(" The provided value is moved into the instance, ", - "potentially invalidating previously taken references.")] - $($( - #[doc = ""] - #[$set_move_meta] - )*)? - fn []( - instance: ::core::ptr::NonNull<$object_type>, - value: NonNull<$prop_type>, - ) { - let instance = unsafe { $crate::macros::nonnull_as_mut!(instance) }; - let value = unsafe { $crate::mem::heap_remove(value) }; - $($( - let $set_move_value = value; - let value = $set_move_expr; - )?)? - instance.$prop_name = value; - } - )? )+ ); } diff --git a/src/packet.rs b/src/packet.rs index 4278fe0..af49fc8 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,72 +1,95 @@ use crate::{ containers::ByteSlice, - macros::{wrap_clone, wrap_fields, wrap_free, wrap_functions}, + macros::{wrap_clone, wrap_fields, wrap_free}, mem::{heap_move_nonnull, heap_move_ok}, }; use servicepoint::{CommandCode, Header, Packet}; use std::ptr::NonNull; -wrap_functions!(sp_packet; +/// Tries to load a [Packet] from the passed array with the specified length. +/// +/// returns: NULL in case of an error, pointer to the allocated packet otherwise +#[no_mangle] +pub unsafe extern "C" fn sp_packet_try_load(data: ByteSlice) -> *mut Packet { + let data = unsafe { data.as_slice() }; + heap_move_ok(servicepoint::Packet::try_from(data)) +} - /// Tries to load a [Packet] from the passed array with the specified length. - /// - /// returns: NULL in case of an error, pointer to the allocated packet otherwise - fn try_load(data: ByteSlice) -> *mut Packet { - let data = unsafe { data.as_slice() }; - heap_move_ok(servicepoint::Packet::try_from(data)) +/// Creates a raw [Packet] from parts. +/// +/// returns: new instance. Will never return null. +#[no_mangle] +pub unsafe extern "C" fn sp_packet_from_parts( + header: Header, + payload: ByteSlice, +) -> NonNull { + let payload = if payload == ByteSlice::INVALID { + None + } else { + Some(Vec::from(unsafe { payload.as_slice() })) + }; + + heap_move_nonnull(Packet { header, payload }) +} + +/// Returns a pointer to the header field of the provided packet. +/// +/// The returned header can be changed and will be valid for the lifetime of the packet. +#[no_mangle] +pub unsafe extern "C" fn sp_packet_get_header_mut( + packet: NonNull, +) -> NonNull
{ + NonNull::from(unsafe { &mut (*packet.as_ptr()).header }) +} + +/// Returns a pointer to the current payload of the provided packet. +/// +/// Returns an [ByteSlice::INVALID] instance in case the packet does not have any payload. +/// +/// The returned memory can be changed and will be valid until a new payload is set. +#[no_mangle] +pub unsafe extern "C" fn sp_packet_get_payload( + packet: NonNull, +) -> ByteSlice { + unsafe { + match &mut (*packet.as_ptr()).payload { + None => ByteSlice::INVALID, + Some(payload) => ByteSlice::from_slice(payload), + } } +} - /// Creates a raw [Packet] from parts. - /// - /// returns: new instance. Will never return null. - fn from_parts(header: Header, payload: ByteSlice) -> NonNull { - let payload = if payload == ByteSlice::INVALID { +/// Sets the payload of the provided packet to the provided data. +/// +/// This makes previous payload pointers invalid. +#[no_mangle] +pub unsafe extern "C" fn sp_packet_set_payload( + packet: NonNull, + data: ByteSlice, +) { + unsafe { + (*packet.as_ptr()).payload = if data == ByteSlice::INVALID { None } else { - Some(Vec::from(unsafe { payload.as_slice() })) - }; - - heap_move_nonnull(Packet { header, payload }) - } - - /// Returns a pointer to the current payload of the provided packet. - /// - /// Returns an [ByteSlice::INVALID] instance in case the packet does not have any payload. - /// - /// The returned memory can be changed and will be valid until a new payload is set. - fn get_payload(packet: NonNull) -> ByteSlice { - unsafe { - match &mut (*packet.as_ptr()).payload { - None => ByteSlice::INVALID, - Some(payload) => ByteSlice::from_slice(payload), - } + Some(data.as_slice().to_vec()) } } +} - /// Sets the payload of the provided packet to the provided data. - /// - /// This makes previous payload pointers invalid. - fn set_payload(packet: NonNull, data: ByteSlice) { - unsafe { - (*packet.as_ptr()).payload = if data == ByteSlice::INVALID { - None - } else { - Some(data.as_slice().to_vec()) - } - } +/// Serialize the packet into the provided buffer. +/// +/// # Panics +/// +/// - if the buffer is not big enough to hold header+payload. +#[no_mangle] +pub unsafe extern "C" fn sp_packet_serialize_to( + packet: NonNull, + mut buffer: ByteSlice, +) { + unsafe { + packet.as_ref().serialize_to(buffer.as_slice_mut()); } - - /// Serialize the packet into the provided buffer. - /// - /// # Panics - /// - /// - if the buffer is not big enough to hold header+payload. - fn serialize_to(packet: NonNull, buffer: ByteSlice) -> usize { - unsafe { - packet.as_ref().serialize_to(buffer.as_slice_mut()).unwrap_or(0) - } - } -); +} wrap_clone!(sp_packet::Packet); wrap_free!(sp_packet::Packet); @@ -75,29 +98,25 @@ wrap_fields!( sp_packet::Packet; prop header: Header { get(); - mut get(); set(value); }; ); -wrap_functions!(sp; - - /// Converts u16 into [CommandCode]. - /// - /// If the provided value is not valid, false is returned and result is not changed. - fn u16_to_command_code( - code: u16, - result: *mut CommandCode, - ) -> bool { - match CommandCode::try_from(code) { - Ok(code) => { - unsafe { - *result = code; - } - true +/// Converts u16 into [CommandCode]. +/// +/// If the provided value is not valid, false is returned and result is not changed. +#[no_mangle] +pub unsafe extern "C" fn sp_u16_to_command_code( + code: u16, + result: *mut CommandCode, +) -> bool { + match CommandCode::try_from(code) { + Ok(code) => { + unsafe { + *result = code; } - Err(_) => false, + true } + Err(_) => false, } - -); +} diff --git a/src/udp.rs b/src/udp.rs index cb96547..e18476a 100644 --- a/src/udp.rs +++ b/src/udp.rs @@ -1,6 +1,6 @@ use crate::{ commands::{CommandTag, SPCommand}, - macros::{wrap_free, wrap_functions}, + macros::wrap_free, mem::{heap_move_ok, heap_remove}, }; use servicepoint::{Header, Packet, UdpSocketExt}; @@ -10,122 +10,138 @@ use std::{ ptr::NonNull, }; -wrap_free!(sp_udp::UdpSocket); +/// Creates a new instance of [UdpSocket]. +/// +/// returns: NULL if connection fails, or connected instance +/// +/// # Examples +/// +/// ```C +/// UdpSocket connection = sp_udp_open("172.23.42.29:2342"); +/// if (connection != NULL) +/// sp_udp_send_command(connection, sp_command_clear()); +/// ``` +#[no_mangle] +pub unsafe extern "C" fn sp_udp_open(host: NonNull) -> *mut UdpSocket { + let host = unsafe { CStr::from_ptr(host.as_ptr()) } + .to_str() + .expect("Bad encoding"); -wrap_functions!(sp_udp; + heap_move_ok(UdpSocket::bind_connect(host)) +} - /// Creates a new instance of [UdpSocket]. - /// - /// returns: NULL if connection fails, or connected instance - /// - /// # Examples - /// - /// ```C - /// UdpSocket connection = sp_udp_open("172.23.42.29:2342"); - /// if (connection != NULL) - /// sp_udp_send_command(connection, sp_command_clear()); - /// ``` - fn open(host: NonNull) -> *mut UdpSocket { - let host = unsafe { CStr::from_ptr(host.as_ptr()) } - .to_str() - .expect("Bad encoding"); +/// Creates a new instance of [UdpSocket]. +/// +/// returns: NULL if connection fails, or connected instance +/// +/// # Examples +/// +/// ```C +/// UdpSocket connection = sp_udp_open_ipv4(172, 23, 42, 29, 2342); +/// if (connection != NULL) +/// sp_udp_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 UdpSocket { + let addr = SocketAddrV4::new(Ipv4Addr::from([ip1, ip2, ip3, ip4]), port); + heap_move_ok(UdpSocket::bind_connect(addr)) +} - heap_move_ok(UdpSocket::bind_connect(host)) - } +/// Sends a [Packet] to the display using the [UdpSocket]. +/// +/// The passed `packet` gets consumed. +/// +/// returns: true in case of success +#[no_mangle] +pub unsafe extern "C" fn sp_udp_send_packet( + connection: NonNull, + packet: NonNull, +) -> bool { + let packet = unsafe { heap_remove(packet) }; + unsafe { connection.as_ref().send(&Vec::from(packet)) }.is_ok() +} - /// Creates a new instance of [UdpSocket]. - /// - /// returns: NULL if connection fails, or connected instance - /// - /// # Examples - /// - /// ```C - /// UdpSocket connection = sp_udp_open_ipv4(172, 23, 42, 29, 2342); - /// if (connection != NULL) - /// sp_udp_send_command(connection, sp_command_clear()); - /// ``` - fn open_ipv4(ip1: u8, ip2: u8, ip3: u8, ip4: u8, port: u16) -> *mut UdpSocket { - let addr = SocketAddrV4::new(Ipv4Addr::from([ip1, ip2, ip3, ip4]), port); - heap_move_ok(UdpSocket::bind_connect(addr)) - } - - /// Sends a [Packet] to the display using the [UdpSocket]. - /// - /// The passed `packet` gets consumed. - /// - /// returns: true in case of success - fn send_packet(connection: NonNull, packet: NonNull) -> bool { - let packet = unsafe { heap_remove(packet) }; - unsafe { connection.as_ref().send(&Vec::from(packet)) }.is_ok() - } - - /// Sends a [SPCommand] to the display using the [UdpSocket]. - /// - /// The passed `command` gets consumed. - /// - /// returns: true in case of success - /// - /// # Examples - /// - /// ```C - /// sp_udp_send_command(connection, sp_command_brightness(5)); - /// ``` - fn send_command(connection: NonNull, command: SPCommand) -> bool { - unsafe { - match command.tag { - CommandTag::Invalid => return false, - CommandTag::Bitmap => connection - .as_ref() - .send_command(heap_remove(command.data.bitmap)), - CommandTag::BitVec => connection - .as_ref() - .send_command(heap_remove(command.data.bitvec)), - CommandTag::BrightnessGrid => connection - .as_ref() - .send_command(heap_remove(command.data.brightness_grid)), - CommandTag::CharGrid => connection - .as_ref() - .send_command(heap_remove(command.data.char_grid)), - CommandTag::Cp437Grid => connection - .as_ref() - .send_command(heap_remove(command.data.cp437_grid)), - CommandTag::GlobalBrightness => connection - .as_ref() - .send_command(heap_remove(command.data.global_brightness)), - CommandTag::Clear => connection - .as_ref() - .send_command(heap_remove(command.data.clear)), - CommandTag::HardReset => connection - .as_ref() - .send_command(heap_remove(command.data.hard_reset)), - CommandTag::FadeOut => connection - .as_ref() - .send_command(heap_remove(command.data.fade_out)), - CommandTag::BitmapLegacy => connection - .as_ref() - .send_command(heap_remove(command.data.bitmap_legacy)), - } +/// Sends a [SPCommand] to the display using the [UdpSocket]. +/// +/// The passed `command` gets consumed. +/// +/// returns: true in case of success +/// +/// # Examples +/// +/// ```C +/// sp_udp_send_command(connection, sp_command_brightness(5)); +/// ``` +#[no_mangle] +pub unsafe extern "C" fn sp_udp_send_command( + connection: NonNull, + command: SPCommand, +) -> bool { + unsafe { + match command.tag { + CommandTag::Invalid => return false, + CommandTag::Bitmap => connection + .as_ref() + .send_command(heap_remove(command.data.bitmap)), + CommandTag::BitVec => connection + .as_ref() + .send_command(heap_remove(command.data.bitvec)), + CommandTag::BrightnessGrid => connection + .as_ref() + .send_command(heap_remove(command.data.brightness_grid)), + CommandTag::CharGrid => connection + .as_ref() + .send_command(heap_remove(command.data.char_grid)), + CommandTag::Cp437Grid => connection + .as_ref() + .send_command(heap_remove(command.data.cp437_grid)), + CommandTag::GlobalBrightness => connection + .as_ref() + .send_command(heap_remove(command.data.global_brightness)), + CommandTag::Clear => connection + .as_ref() + .send_command(heap_remove(command.data.clear)), + CommandTag::HardReset => connection + .as_ref() + .send_command(heap_remove(command.data.hard_reset)), + CommandTag::FadeOut => connection + .as_ref() + .send_command(heap_remove(command.data.fade_out)), + CommandTag::BitmapLegacy => connection + .as_ref() + .send_command(heap_remove(command.data.bitmap_legacy)), } - .is_some() } + .is_some() +} - /// Sends a [Header] to the display using the [UdpSocket]. - /// - /// returns: true in case of success - /// - /// # Examples - /// - /// ```C - /// sp_udp_send_header(connection, sp_command_brightness(5)); - /// ``` - fn send_header(udp_connection: NonNull, header: Header) -> bool { - let packet = Packet { - header, - payload: None, - }; - unsafe { udp_connection.as_ref() } - .send(&Vec::from(packet)) - .is_ok() - } +/// Sends a [Header] to the display using the [UdpSocket]. +/// +/// returns: true in case of success +/// +/// # Examples +/// +/// ```C +/// sp_udp_send_header(connection, sp_command_brightness(5)); +/// ``` +#[no_mangle] +pub unsafe extern "C" fn sp_udp_send_header( + udp_connection: NonNull, + header: Header, +) -> bool { + let packet = Packet { + header, + payload: None, + }; + unsafe { udp_connection.as_ref() } + .send(&Vec::from(packet)) + .is_ok() +} -); +wrap_free!(sp_udp::UdpSocket);