From 4bb505650c9bd8cc85bbb5dff4aacc15c453573c Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sun, 12 May 2024 18:28:53 +0200 Subject: [PATCH] fix c api, add usage example --- .gitignore | 3 +- examples/lang_c/CMakeLists.txt | 23 +++ examples/lang_c/main.c | 25 +++ servicepoint2/Cargo.toml | 4 + servicepoint2/bindings.h | 186 ----------------- servicepoint2/build.rs | 6 +- servicepoint2/sp2-bindings.h | 353 ++++++++++++++++++++++++++++++++ servicepoint2/src/bit_vec.rs | 26 ++- servicepoint2/src/byte_grid.rs | 29 ++- servicepoint2/src/command.rs | 34 +-- servicepoint2/src/connection.rs | 7 +- servicepoint2/src/pixel_grid.rs | 29 ++- 12 files changed, 488 insertions(+), 237 deletions(-) create mode 100644 examples/lang_c/CMakeLists.txt create mode 100644 examples/lang_c/main.c delete mode 100644 servicepoint2/bindings.h create mode 100644 servicepoint2/sp2-bindings.h diff --git a/.gitignore b/.gitignore index 5bd05d6..1e859a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ target -.idea \ No newline at end of file +.idea +cmake-* diff --git a/examples/lang_c/CMakeLists.txt b/examples/lang_c/CMakeLists.txt new file mode 100644 index 0000000..0ae7052 --- /dev/null +++ b/examples/lang_c/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.28) +project(lang_c C) +set(CMAKE_C_STANDARD 17) + +include(FetchContent) +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git + GIT_TAG v0.5 # Optionally specify a commit hash, version tag or branch here +) +FetchContent_MakeAvailable(Corrosion) + +# Import targets defined in a package or workspace manifest `Cargo.toml` file +corrosion_import_crate( + MANIFEST_PATH ../../servicepoint2/Cargo.toml + PROFILE release + FEATURES c-api + ALL_FEATURES) + +add_executable(lang_c main.c) + +target_link_libraries(lang_c PRIVATE servicepoint2) + diff --git a/examples/lang_c/main.c b/examples/lang_c/main.c new file mode 100644 index 0000000..04476e3 --- /dev/null +++ b/examples/lang_c/main.c @@ -0,0 +1,25 @@ +#include +#include "../../servicepoint2/sp2-bindings.h" + +int main(void) { + sp2_Connection *connection = sp2_connection_open("localhost:2342"); + if (connection == NULL) + return 1; + + sp2_Command *command = sp2_command_clear(); + if (command == NULL) + return 2; + if (!sp2_connection_send(connection, command)) + return 3; + + sp2_PixelGrid *pixels = sp2_pixel_grid_new(sp2_PIXEL_WIDTH, sp2_PIXEL_HEIGHT); + sp2_pixel_grid_fill(pixels, true); + command = sp2_command_bitmap_linear_win(0, 0, pixels); + if (command == NULL) + return 4; + if (!sp2_connection_send(connection, command)) + return 5; + + sp2_connection_dealloc(connection); + return 0; +} diff --git a/servicepoint2/Cargo.toml b/servicepoint2/Cargo.toml index a966e40..3ff212a 100644 --- a/servicepoint2/Cargo.toml +++ b/servicepoint2/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://docs.rs/crate/servicepoint2" repository = "https://github.com/kaesaecracker/servicepoint" readme = "../README.md" +[lib] +crate-type = ["staticlib", "rlib"] + [dependencies] log = "0.4" flate2 = { version = "1.0", optional = true } @@ -23,6 +26,7 @@ compression-bz = ["dep:bzip2", "compression"] compression-lz = ["dep:lz4", "compression"] compression-zs = ["dep:zstd", "compression"] compression = [] +c-api = [] [build-dependencies] cbindgen = "0.26.0" diff --git a/servicepoint2/bindings.h b/servicepoint2/bindings.h deleted file mode 100644 index 0c4cb8c..0000000 --- a/servicepoint2/bindings.h +++ /dev/null @@ -1,186 +0,0 @@ -#include -#include -#include -#include - -/** - * size of a single tile in one dimension - */ -#define sp2_TILE_SIZE 8 - -/** - * tile count in the x-direction - */ -#define sp2_TILE_WIDTH 56 - -/** - * tile count in the y-direction - */ -#define sp2_TILE_HEIGHT 20 - -/** - * screen width in pixels - */ -#define sp2_PIXEL_WIDTH (sp2_TILE_WIDTH * sp2_TILE_SIZE) - -/** - * screen height in pixels - */ -#define sp2_PIXEL_HEIGHT (sp2_TILE_HEIGHT * sp2_TILE_SIZE) - -/** - * pixel count on whole screen - */ -#define sp2_PIXEL_COUNT ((uintptr_t)sp2_PIXEL_WIDTH * (uintptr_t)sp2_PIXEL_HEIGHT) - -/** - * Specifies the kind of compression to use. Availability depends on features. - */ -enum sp2_CompressionCode { - Uncompressed = 0, - Gz = 26490, - Bz = 25210, - Lz = 27770, - Zs = 31347, -}; -typedef uint16_t sp2_CompressionCode; - -/** - * A vector of bits - */ -typedef struct sp2_BitVec sp2_BitVec; - -/** - * A grid of bytes - */ -typedef struct sp2_ByteGrid sp2_ByteGrid; - -/** - * A command to send to the display. - */ -typedef struct sp2_Command sp2_Command; - -/** - * A connection to the display. - */ -typedef struct sp2_Connection sp2_Connection; - -/** - * A grid of pixels stored in packed bytes. - */ -typedef struct sp2_PixelGrid sp2_PixelGrid; - -typedef uint8_t sp2_Brightness; - -typedef uint16_t sp2_Offset; - -/** - * Tries to load a command from the passed array with the specified length. - * - * returns: NULL in case of an error, pointer to the allocated command otherwise - */ -struct sp2_Command *command_try_load(const uint8_t *data, uintptr_t length); - -/** - * Clones a `Command` instance - */ -struct sp2_Command *command_clone(const struct sp2_Command *original); - -/** - * Allocates a new `Command::Clear` instance - */ -struct sp2_Command *command_clear(void); - -/** - * Allocates a new `Command::HardReset` instance - */ -struct sp2_Command *command_hard_reset(void); - -/** - * Allocates a new `Command::FadeOut` instance - */ -struct sp2_Command *command_fade_out(void); - -/** - * Allocates a new `Command::Brightness` instance - */ -struct sp2_Command *command_brightness(sp2_Brightness brightness); - -/** - * Allocates a new `Command::CharBrightness` instance. - * The passed `ByteGrid` gets deallocated in the process. - */ -struct sp2_Command *command_char_brightness(uint16_t x, uint16_t y, struct sp2_ByteGrid *byte_grid); - -/** - * Allocates a new `Command::BitmapLinear` instance. - * The passed `BitVec` gets deallocated in the process. - */ -struct sp2_Command *command_bitmap_linear(sp2_Offset offset, - struct sp2_BitVec *bit_vec, - sp2_CompressionCode compression); - -/** - * Allocates a new `Command::BitmapLinearAnd` instance. - * The passed `BitVec` gets deallocated in the process. - */ -struct sp2_Command *command_bitmap_linear_and(sp2_Offset offset, - struct sp2_BitVec *bit_vec, - sp2_CompressionCode compression); - -/** - * Allocates a new `Command::BitmapLinearOr` instance. - * The passed `BitVec` gets deallocated in the process. - */ -struct sp2_Command *command_bitmap_linear_or(sp2_Offset offset, - struct sp2_BitVec *bit_vec, - sp2_CompressionCode compression); - -/** - * Allocates a new `Command::BitmapLinearXor` instance. - * The passed `BitVec` gets deallocated in the process. - */ -struct sp2_Command *command_bitmap_linear_xor(sp2_Offset offset, - struct sp2_BitVec *bit_vec, - sp2_CompressionCode compression); - -/** - * Allocates a new `Command::Cp437Data` instance. - * The passed `ByteGrid` gets deallocated in the process. - */ -struct sp2_Command *command_cp437_data(uint16_t x, uint16_t y, struct sp2_ByteGrid *byte_grid); - -/** - * Allocates a new `Command::BitmapLinearWin` instance. - * The passed `PixelGrid` gets deallocated in the process. - */ -struct sp2_Command *command_bitmap_linear_win(uint16_t x, - uint16_t y, - struct sp2_PixelGrid *byte_grid); - -/** - * Deallocates a command. Note that connection_send does this implicitly, so you only need - * to do this if you use the library for parsing commands. - */ -void command_dealloc(struct sp2_Command *ptr); - -/** - * Creates a new instance of Connection. - * The returned instance has to be deallocated with `connection_dealloc`. - * - * returns: NULL if connection fails or connected instance - * - * Panics: bad string encoding - */ -struct sp2_Connection *connection_open(const char *host); - -/** - * Sends the command instance. The instance is consumed / destroyed and cannot be used after this call. - */ -bool connection_send(const struct sp2_Connection *connection, - struct sp2_Command *command_ptr); - -/** - * Closes and deallocates a connection instance - */ -void connection_dealloc(struct sp2_Connection *ptr); diff --git a/servicepoint2/build.rs b/servicepoint2/build.rs index 5088a95..033e717 100644 --- a/servicepoint2/build.rs +++ b/servicepoint2/build.rs @@ -6,11 +6,15 @@ use cbindgen::Language; fn main() { let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + println!("cargo:rerun-if-changed=src"); + cbindgen::Builder::new() .with_crate(crate_dir) .with_item_prefix("sp2_") .with_language(Language::C) + .with_cpp_compat(true) + .with_parse_expand_all_features(true) .generate() .expect("Unable to generate bindings") - .write_to_file("bindings.h"); + .write_to_file("sp2-bindings.h"); } \ No newline at end of file diff --git a/servicepoint2/sp2-bindings.h b/servicepoint2/sp2-bindings.h new file mode 100644 index 0000000..cb4704e --- /dev/null +++ b/servicepoint2/sp2-bindings.h @@ -0,0 +1,353 @@ +#include +#include +#include +#include + +/** + * size of a single tile in one dimension + */ +#define sp2_TILE_SIZE 8 + +/** + * tile count in the x-direction + */ +#define sp2_TILE_WIDTH 56 + +/** + * tile count in the y-direction + */ +#define sp2_TILE_HEIGHT 20 + +/** + * screen width in pixels + */ +#define sp2_PIXEL_WIDTH (sp2_TILE_WIDTH * sp2_TILE_SIZE) + +/** + * screen height in pixels + */ +#define sp2_PIXEL_HEIGHT (sp2_TILE_HEIGHT * sp2_TILE_SIZE) + +/** + * pixel count on whole screen + */ +#define sp2_PIXEL_COUNT ((uintptr_t)sp2_PIXEL_WIDTH * (uintptr_t)sp2_PIXEL_HEIGHT) + +/** + * Specifies the kind of compression to use. Availability depends on features. + */ +enum sp2_CompressionCode +#ifdef __cplusplus + : uint16_t +#endif // __cplusplus + { + Uncompressed = 0, + Gz = 26490, + Bz = 25210, + Lz = 27770, + Zs = 31347, +}; +#ifndef __cplusplus +typedef uint16_t sp2_CompressionCode; +#endif // __cplusplus + +/** + * A vector of bits + */ +typedef struct sp2_BitVec sp2_BitVec; + +/** + * A grid of bytes + */ +typedef struct sp2_ByteGrid sp2_ByteGrid; + +/** + * A command to send to the display. + */ +typedef struct sp2_Command sp2_Command; + +/** + * A connection to the display. + */ +typedef struct sp2_Connection sp2_Connection; + +/** + * A grid of pixels stored in packed bytes. + */ +typedef struct sp2_PixelGrid sp2_PixelGrid; + +typedef uint8_t sp2_Brightness; + +typedef uint16_t sp2_Offset; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Creates a new `BitVec` instance. + * The returned instance has to be freed with `bit_vec_dealloc`. + */ +struct sp2_BitVec *sp2_bit_vec_new(uintptr_t size); + +/** + * Loads a `BitVec` from the provided data. + * The returned instance has to be freed with `bit_vec_dealloc`. + */ +struct sp2_BitVec *sp2_bit_vec_load(const uint8_t *data, uintptr_t data_length); + +/** + * Clones a `BitVec`. + * The returned instance has to be freed with `bit_vec_dealloc`. + */ +struct sp2_BitVec *sp2_bit_vec_clone(const struct sp2_BitVec *this_); + +/** + * Deallocates a `BitVec`. + * + * Note: do not call this if the grid has been consumed in another way, e.g. to create a command. + */ +void sp2_bit_vec_dealloc(struct sp2_BitVec *this_); + +/** + * Gets the value of a bit from the `BitVec`. + */ +bool sp2_bit_vec_get(const struct sp2_BitVec *this_, uintptr_t index); + +/** + * Sets the value of a bit in the `BitVec`. + */ +bool sp2_bit_vec_set(struct sp2_BitVec *this_, uintptr_t index, bool value); + +/** + * Sets the value of all bits in the `BitVec`. + */ +void sp2_bit_vec_fill(struct sp2_BitVec *this_, bool value); + +/** + * Gets the length of the `BitVec` in bits. + */ +uintptr_t sp2_bit_vec_len(const struct sp2_BitVec *this_); + +/** + * Creates a new `ByteGrid` instance. + * The returned instance has to be freed with `byte_grid_dealloc`. + */ +struct sp2_ByteGrid *sp2_byte_grid_new(uintptr_t width, uintptr_t height); + +/** + * Loads a `ByteGrid` with the specified dimensions from the provided data. + * The returned instance has to be freed with `byte_grid_dealloc`. + */ +struct sp2_ByteGrid *sp2_byte_grid_load(uintptr_t width, + uintptr_t height, + const uint8_t *data, + uintptr_t data_length); + +/** + * Clones a `ByteGrid`. + * The returned instance has to be freed with `byte_grid_dealloc`. + */ +struct sp2_ByteGrid *sp2_byte_grid_clone(const struct sp2_ByteGrid *this_); + +/** + * Deallocates a `ByteGrid`. + * + * Note: do not call this if the grid has been consumed in another way, e.g. to create a command. + */ +void sp2_byte_grid_dealloc(struct sp2_ByteGrid *this_); + +/** + * Get the current value at the specified position + */ +uint8_t sp2_byte_grid_get(const struct sp2_ByteGrid *this_, uintptr_t x, uintptr_t y); + +/** + * Sets the current value at the specified position + */ +void sp2_byte_grid_set(struct sp2_ByteGrid *this_, uintptr_t x, uintptr_t y, uint8_t value); + +/** + * Fills the whole `ByteGrid` with the specified value + */ +void sp2_byte_grid_fill(struct sp2_ByteGrid *this_, uint8_t value); + +/** + * Gets the width in pixels of the `ByteGrid` instance. + */ +uintptr_t sp2_byte_grid_width(const struct sp2_PixelGrid *this_); + +/** + * Gets the height in pixels of the `ByteGrid` instance. + */ +uintptr_t sp2_byte_grid_height(const struct sp2_PixelGrid *this_); + +/** + * Tries to load a command from the passed array with the specified length. + * + * returns: NULL in case of an error, pointer to the allocated command otherwise + */ +struct sp2_Command *sp2_command_try_load(const uint8_t *data, uintptr_t length); + +/** + * Clones a `Command` instance + */ +struct sp2_Command *sp2_command_clone(const struct sp2_Command *original); + +/** + * Allocates a new `Command::Clear` instance + */ +struct sp2_Command *sp2_command_clear(void); + +/** + * Allocates a new `Command::HardReset` instance + */ +struct sp2_Command *sp2_command_hard_reset(void); + +/** + * Allocates a new `Command::FadeOut` instance + */ +struct sp2_Command *sp2_command_fade_out(void); + +/** + * Allocates a new `Command::Brightness` instance + */ +struct sp2_Command *sp2_command_brightness(sp2_Brightness brightness); + +/** + * Allocates a new `Command::CharBrightness` instance. + * The passed `ByteGrid` gets deallocated in the process. + */ +struct sp2_Command *sp2_command_char_brightness(uint16_t x, + uint16_t y, + struct sp2_ByteGrid *byte_grid); + +/** + * Allocates a new `Command::BitmapLinear` instance. + * The passed `BitVec` gets deallocated in the process. + */ +struct sp2_Command *sp2_command_bitmap_linear(sp2_Offset offset, + struct sp2_BitVec *bit_vec, + sp2_CompressionCode compression); + +/** + * Allocates a new `Command::BitmapLinearAnd` instance. + * The passed `BitVec` gets deallocated in the process. + */ +struct sp2_Command *sp2_command_bitmap_linear_and(sp2_Offset offset, + struct sp2_BitVec *bit_vec, + sp2_CompressionCode compression); + +/** + * Allocates a new `Command::BitmapLinearOr` instance. + * The passed `BitVec` gets deallocated in the process. + */ +struct sp2_Command *sp2_command_bitmap_linear_or(sp2_Offset offset, + struct sp2_BitVec *bit_vec, + sp2_CompressionCode compression); + +/** + * Allocates a new `Command::BitmapLinearXor` instance. + * The passed `BitVec` gets deallocated in the process. + */ +struct sp2_Command *sp2_command_bitmap_linear_xor(sp2_Offset offset, + struct sp2_BitVec *bit_vec, + sp2_CompressionCode compression); + +/** + * Allocates a new `Command::Cp437Data` instance. + * The passed `ByteGrid` gets deallocated in the process. + */ +struct sp2_Command *sp2_command_cp437_data(uint16_t x, uint16_t y, struct sp2_ByteGrid *byte_grid); + +/** + * Allocates a new `Command::BitmapLinearWin` instance. + * The passed `PixelGrid` gets deallocated in the process. + */ +struct sp2_Command *sp2_command_bitmap_linear_win(uint16_t x, + uint16_t y, + struct sp2_PixelGrid *byte_grid); + +/** + * Deallocates a command. Note that connection_send does this implicitly, so you only need + * to do this if you use the library for parsing commands. + */ +void sp2_command_dealloc(struct sp2_Command *ptr); + +/** + * Creates a new instance of Connection. + * The returned instance has to be deallocated with `connection_dealloc`. + * + * returns: NULL if connection fails or connected instance + * + * Panics: bad string encoding + */ +struct sp2_Connection *sp2_connection_open(const char *host); + +/** + * Sends the command instance. The instance is consumed / destroyed and cannot be used after this call. + */ +bool sp2_connection_send(const struct sp2_Connection *connection, + struct sp2_Command *command_ptr); + +/** + * Closes and deallocates a connection instance + */ +void sp2_connection_dealloc(struct sp2_Connection *ptr); + +/** + * Creates a new `PixelGrid` instance. + * The returned instance has to be freed with `pixel_grid_dealloc`. + */ +struct sp2_PixelGrid *sp2_pixel_grid_new(uintptr_t width, uintptr_t height); + +/** + * Loads a `PixelGrid` with the specified dimensions from the provided data. + * The returned instance has to be freed with `pixel_grid_dealloc`. + */ +struct sp2_PixelGrid *sp2_pixel_grid_load(uintptr_t width, + uintptr_t height, + const uint8_t *data, + uintptr_t data_length); + +/** + * Clones a `PixelGrid`. + * The returned instance has to be freed with `pixel_grid_dealloc`. + */ +struct sp2_PixelGrid *sp2_pixel_grid_clone(const struct sp2_PixelGrid *this_); + +/** + * Deallocates a `PixelGrid`. + * + * Note: do not call this if the grid has been consumed in another way, e.g. to create a command. + */ +void sp2_pixel_grid_dealloc(struct sp2_PixelGrid *this_); + +/** + * Get the current value at the specified position + */ +bool sp2_pixel_grid_get(const struct sp2_PixelGrid *this_, uintptr_t x, uintptr_t y); + +/** + * Sets the current value at the specified position + */ +void sp2_pixel_grid_set(struct sp2_PixelGrid *this_, uintptr_t x, uintptr_t y, bool value); + +/** + * Fills the whole `PixelGrid` with the specified value + */ +void sp2_pixel_grid_fill(struct sp2_PixelGrid *this_, bool value); + +/** + * Gets the width in pixels of the `PixelGrid` instance. + */ +uintptr_t sp2_pixel_grid_width(const struct sp2_PixelGrid *this_); + +/** + * Gets the height in pixels of the `PixelGrid` instance. + */ +uintptr_t sp2_pixel_grid_height(const struct sp2_PixelGrid *this_); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/servicepoint2/src/bit_vec.rs b/servicepoint2/src/bit_vec.rs index 8451591..2f28c19 100644 --- a/servicepoint2/src/bit_vec.rs +++ b/servicepoint2/src/bit_vec.rs @@ -106,53 +106,61 @@ impl std::fmt::Debug for BitVec { } } -#[allow(unused)] +#[cfg(feature = "c-api")] pub mod c_api { use crate::BitVec; /// Creates a new `BitVec` instance. /// The returned instance has to be freed with `bit_vec_dealloc`. - pub unsafe extern "C" fn bit_vec_new(size: usize) -> *mut BitVec { + #[no_mangle] + pub unsafe extern "C" fn sp2_bit_vec_new(size: usize) -> *mut BitVec { Box::into_raw(Box::new(BitVec::new(size))) } /// Loads a `BitVec` from the provided data. /// The returned instance has to be freed with `bit_vec_dealloc`. - pub unsafe extern "C" fn byte_grid_load(data: *const u8, data_length: usize) -> *mut BitVec { + #[no_mangle] + pub unsafe extern "C" fn sp2_bit_vec_load(data: *const u8, data_length: usize) -> *mut BitVec { let data = std::slice::from_raw_parts(data, data_length); Box::into_raw(Box::new(BitVec::from(data))) } /// Clones a `BitVec`. /// The returned instance has to be freed with `bit_vec_dealloc`. - pub unsafe extern "C" fn byte_grid_clone(this: *const BitVec) -> *mut BitVec { + #[no_mangle] + pub unsafe extern "C" fn sp2_bit_vec_clone(this: *const BitVec) -> *mut BitVec { Box::into_raw(Box::new((*this).clone())) } /// Deallocates a `BitVec`. /// /// Note: do not call this if the grid has been consumed in another way, e.g. to create a command. - pub unsafe extern "C" fn byte_grid_dealloc(this: *mut BitVec) { + #[no_mangle] + pub unsafe extern "C" fn sp2_bit_vec_dealloc(this: *mut BitVec) { _ = Box::from_raw(this); } /// Gets the value of a bit from the `BitVec`. - pub unsafe extern "C" fn byte_grid_get(this: *const BitVec, index: usize) -> bool { + #[no_mangle] + pub unsafe extern "C" fn sp2_bit_vec_get(this: *const BitVec, index: usize) -> bool { (*this).get(index) } /// Sets the value of a bit in the `BitVec`. - pub unsafe extern "C" fn byte_grid_set(this: *mut BitVec, index: usize, value: bool) -> bool { + #[no_mangle] + pub unsafe extern "C" fn sp2_bit_vec_set(this: *mut BitVec, index: usize, value: bool) -> bool { (*this).set(index, value) } /// Sets the value of all bits in the `BitVec`. - pub unsafe extern "C" fn byte_grid_fill(this: *mut BitVec, value: bool) { + #[no_mangle] + pub unsafe extern "C" fn sp2_bit_vec_fill(this: *mut BitVec, value: bool) { (*this).fill(value) } /// Gets the length of the `BitVec` in bits. - pub unsafe extern "C" fn byte_grid_len(this: *const BitVec) -> usize{ + #[no_mangle] + pub unsafe extern "C" fn sp2_bit_vec_len(this: *const BitVec) -> usize{ (*this).len() } } diff --git a/servicepoint2/src/byte_grid.rs b/servicepoint2/src/byte_grid.rs index c5f10cf..a41468e 100644 --- a/servicepoint2/src/byte_grid.rs +++ b/servicepoint2/src/byte_grid.rs @@ -58,59 +58,68 @@ impl Into> for ByteGrid { } } -#[allow(unused)] +#[cfg(feature = "c-api")] pub mod c_api { use crate::{ByteGrid, PixelGrid}; /// Creates a new `ByteGrid` instance. /// The returned instance has to be freed with `byte_grid_dealloc`. - pub unsafe extern "C" fn byte_grid_new(width: usize, height: usize) -> *mut ByteGrid { + #[no_mangle] + pub unsafe extern "C" fn sp2_byte_grid_new(width: usize, height: usize) -> *mut ByteGrid { Box::into_raw(Box::new(ByteGrid::new(width, height))) } /// Loads a `ByteGrid` with the specified dimensions from the provided data. /// The returned instance has to be freed with `byte_grid_dealloc`. - pub unsafe extern "C" fn byte_grid_load(width: usize, height: usize, data: *const u8, data_length: usize) -> *mut ByteGrid { + #[no_mangle] + pub unsafe extern "C" fn sp2_byte_grid_load(width: usize, height: usize, data: *const u8, data_length: usize) -> *mut ByteGrid { let data = std::slice::from_raw_parts(data, data_length); Box::into_raw(Box::new(ByteGrid::load(width, height, data))) } /// Clones a `ByteGrid`. /// The returned instance has to be freed with `byte_grid_dealloc`. - pub unsafe extern "C" fn byte_grid_clone(this: *const ByteGrid) -> *mut ByteGrid { + #[no_mangle] + pub unsafe extern "C" fn sp2_byte_grid_clone(this: *const ByteGrid) -> *mut ByteGrid { Box::into_raw(Box::new((*this).clone())) } /// Deallocates a `ByteGrid`. /// /// Note: do not call this if the grid has been consumed in another way, e.g. to create a command. - pub unsafe extern "C" fn byte_grid_dealloc(this: *mut ByteGrid) { + #[no_mangle] + pub unsafe extern "C" fn sp2_byte_grid_dealloc(this: *mut ByteGrid) { _ = Box::from_raw(this); } /// Get the current value at the specified position - pub unsafe extern "C" fn byte_grid_get(this: *const ByteGrid, x: usize, y: usize) -> u8 { + #[no_mangle] + pub unsafe extern "C" fn sp2_byte_grid_get(this: *const ByteGrid, x: usize, y: usize) -> u8 { (*this).get(x, y) } /// Sets the current value at the specified position - pub unsafe extern "C" fn byte_grid_set(this: *mut ByteGrid, x: usize, y: usize, value: u8) { + #[no_mangle] + pub unsafe extern "C" fn sp2_byte_grid_set(this: *mut ByteGrid, x: usize, y: usize, value: u8) { (*this).set(x, y, value); } /// Fills the whole `ByteGrid` with the specified value - pub unsafe extern "C" fn byte_grid_fill(this: *mut ByteGrid, value: u8) { + #[no_mangle] + pub unsafe extern "C" fn sp2_byte_grid_fill(this: *mut ByteGrid, value: u8) { (*this).fill(value); } /// Gets the width in pixels of the `ByteGrid` instance. - pub unsafe extern "C" fn pixel_grid_width(this: *const PixelGrid) -> usize { + #[no_mangle] + pub unsafe extern "C" fn sp2_byte_grid_width(this: *const PixelGrid) -> usize { (*this).width } /// Gets the height in pixels of the `ByteGrid` instance. - pub unsafe extern "C" fn pixel_grid_height(this: *const PixelGrid) -> usize { + #[no_mangle] + pub unsafe extern "C" fn sp2_byte_grid_height(this: *const PixelGrid) -> usize { (*this).height } } \ No newline at end of file diff --git a/servicepoint2/src/command.rs b/servicepoint2/src/command.rs index 85c5437..c921b04 100644 --- a/servicepoint2/src/command.rs +++ b/servicepoint2/src/command.rs @@ -316,18 +316,18 @@ fn packet_into_linear_bitmap( Ok((BitVec::from(&*payload), sub)) } -#[allow(unused)] +#[cfg(feature = "c-api")] pub mod c_api { use std::ptr::null_mut; use crate::{BitVec, Brightness, ByteGrid, Command, CompressionCode, Offset, Origin, Packet, PixelGrid}; - /// Tries to load a command from the passed array with the specified length. + /// Tries to load a `Command` from the passed array with the specified length. /// /// returns: NULL in case of an error, pointer to the allocated command otherwise #[no_mangle] - pub unsafe extern "C" fn command_try_load(data: *const u8, length: usize) -> *mut Command { + pub unsafe extern "C" fn sp2_command_try_load(data: *const u8, length: usize) -> *mut Command { let data = std::slice::from_raw_parts(data, length); let packet = match Packet::try_from(data) { Err(_) => return null_mut(), @@ -342,38 +342,38 @@ pub mod c_api /// Clones a `Command` instance #[no_mangle] - pub unsafe extern "C" fn command_clone(original: *const Command) -> *mut Command { + pub unsafe extern "C" fn sp2_command_clone(original: *const Command) -> *mut Command { Box::into_raw(Box::new((*original).clone())) } /// Allocates a new `Command::Clear` instance #[no_mangle] - pub unsafe extern "C" fn command_clear() -> *mut Command { + pub unsafe extern "C" fn sp2_command_clear() -> *mut Command { Box::into_raw(Box::new(Command::Clear)) } /// Allocates a new `Command::HardReset` instance #[no_mangle] - pub unsafe extern "C" fn command_hard_reset() -> *mut Command { + pub unsafe extern "C" fn sp2_command_hard_reset() -> *mut Command { Box::into_raw(Box::new(Command::HardReset)) } /// Allocates a new `Command::FadeOut` instance #[no_mangle] - pub unsafe extern "C" fn command_fade_out() -> *mut Command { + pub unsafe extern "C" fn sp2_command_fade_out() -> *mut Command { Box::into_raw(Box::new(Command::FadeOut)) } /// Allocates a new `Command::Brightness` instance #[no_mangle] - pub unsafe extern "C" fn command_brightness(brightness: Brightness) -> *mut Command { + pub unsafe extern "C" fn sp2_command_brightness(brightness: Brightness) -> *mut Command { Box::into_raw(Box::new(Command::Brightness(brightness))) } /// Allocates a new `Command::CharBrightness` instance. /// The passed `ByteGrid` gets deallocated in the process. #[no_mangle] - pub unsafe extern "C" fn command_char_brightness(x: u16, y: u16, byte_grid: *mut ByteGrid) -> *mut Command { + pub unsafe extern "C" fn sp2_command_char_brightness(x: u16, y: u16, byte_grid: *mut ByteGrid) -> *mut Command { let byte_grid = *Box::from_raw(byte_grid); Box::into_raw(Box::new(Command::CharBrightness(Origin(x, y), byte_grid))) } @@ -381,7 +381,7 @@ pub mod c_api /// Allocates a new `Command::BitmapLinear` instance. /// The passed `BitVec` gets deallocated in the process. #[no_mangle] - pub unsafe extern "C" fn command_bitmap_linear(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command { + pub unsafe extern "C" fn sp2_command_bitmap_linear(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command { let bit_vec = *Box::from_raw(bit_vec); Box::into_raw(Box::new(Command::BitmapLinear(offset, bit_vec, compression))) } @@ -389,7 +389,7 @@ pub mod c_api /// Allocates a new `Command::BitmapLinearAnd` instance. /// The passed `BitVec` gets deallocated in the process. #[no_mangle] - pub unsafe extern "C" fn command_bitmap_linear_and(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command { + pub unsafe extern "C" fn sp2_command_bitmap_linear_and(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command { let bit_vec = *Box::from_raw(bit_vec); Box::into_raw(Box::new(Command::BitmapLinearAnd(offset, bit_vec, compression))) } @@ -397,7 +397,7 @@ pub mod c_api /// Allocates a new `Command::BitmapLinearOr` instance. /// The passed `BitVec` gets deallocated in the process. #[no_mangle] - pub unsafe extern "C" fn command_bitmap_linear_or(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command { + pub unsafe extern "C" fn sp2_command_bitmap_linear_or(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command { let bit_vec = *Box::from_raw(bit_vec); Box::into_raw(Box::new(Command::BitmapLinearOr(offset, bit_vec, compression))) } @@ -405,7 +405,7 @@ pub mod c_api /// Allocates a new `Command::BitmapLinearXor` instance. /// The passed `BitVec` gets deallocated in the process. #[no_mangle] - pub unsafe extern "C" fn command_bitmap_linear_xor(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command { + pub unsafe extern "C" fn sp2_command_bitmap_linear_xor(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command { let bit_vec = *Box::from_raw(bit_vec); Box::into_raw(Box::new(Command::BitmapLinearXor(offset, bit_vec, compression))) } @@ -413,7 +413,7 @@ pub mod c_api /// Allocates a new `Command::Cp437Data` instance. /// The passed `ByteGrid` gets deallocated in the process. #[no_mangle] - pub unsafe extern "C" fn command_cp437_data(x: u16, y: u16, byte_grid: *mut ByteGrid) -> *mut Command { + pub unsafe extern "C" fn sp2_command_cp437_data(x: u16, y: u16, byte_grid: *mut ByteGrid) -> *mut Command { let byte_grid = *Box::from_raw(byte_grid); Box::into_raw(Box::new(Command::Cp437Data(Origin(x, y), byte_grid))) } @@ -421,15 +421,15 @@ pub mod c_api /// Allocates a new `Command::BitmapLinearWin` instance. /// The passed `PixelGrid` gets deallocated in the process. #[no_mangle] - pub unsafe extern "C" fn command_bitmap_linear_win(x: u16, y: u16, byte_grid: *mut PixelGrid) -> *mut Command { + pub unsafe extern "C" fn sp2_command_bitmap_linear_win(x: u16, y: u16, byte_grid: *mut PixelGrid) -> *mut Command { let byte_grid = *Box::from_raw(byte_grid); Box::into_raw(Box::new(Command::BitmapLinearWin(Origin(x, y), byte_grid))) } - /// Deallocates a command. Note that connection_send does this implicitly, so you only need + /// Deallocates a `Command`. Note that connection_send does this implicitly, so you only need /// to do this if you use the library for parsing commands. #[no_mangle] - pub unsafe extern "C" fn command_dealloc(ptr: *mut Command) { + pub unsafe extern "C" fn sp2_command_dealloc(ptr: *mut Command) { _ = Box::from_raw(ptr); } } \ No newline at end of file diff --git a/servicepoint2/src/connection.rs b/servicepoint2/src/connection.rs index 183e519..493d21c 100644 --- a/servicepoint2/src/connection.rs +++ b/servicepoint2/src/connection.rs @@ -65,6 +65,7 @@ impl Connection { } } +#[cfg(feature = "c-api")] pub mod c_api { use std::ffi::{c_char, CStr}; @@ -79,7 +80,7 @@ pub mod c_api /// /// Panics: bad string encoding #[no_mangle] - pub unsafe extern "C" fn connection_open(host: *const c_char) -> *mut Connection { + pub unsafe extern "C" fn sp2_connection_open(host: *const c_char) -> *mut Connection { let host = CStr::from_ptr(host).to_str().expect("Bad encoding"); let connection = match Connection::open(host) { Err(_) => return null_mut(), @@ -92,14 +93,14 @@ pub mod c_api /// Sends the command instance. The instance is consumed / destroyed and cannot be used after this call. #[no_mangle] - pub unsafe extern "C" fn connection_send(connection: *const Connection, command_ptr: *mut Command) -> bool{ + pub unsafe extern "C" fn sp2_connection_send(connection: *const Connection, command_ptr: *mut Command) -> bool{ let command = Box::from_raw(command_ptr); (*connection).send(*command).is_ok() } /// Closes and deallocates a connection instance #[no_mangle] - pub unsafe extern "C" fn connection_dealloc(ptr: *mut Connection) { + pub unsafe extern "C" fn sp2_connection_dealloc(ptr: *mut Connection) { _ = Box::from_raw(ptr); } } \ No newline at end of file diff --git a/servicepoint2/src/pixel_grid.rs b/servicepoint2/src/pixel_grid.rs index 4092cd2..eb736da 100644 --- a/servicepoint2/src/pixel_grid.rs +++ b/servicepoint2/src/pixel_grid.rs @@ -84,59 +84,68 @@ impl Into> for PixelGrid { } } -#[allow(unused)] +#[cfg(feature = "c-api")] pub mod c_api { use crate::PixelGrid; /// Creates a new `PixelGrid` instance. /// The returned instance has to be freed with `pixel_grid_dealloc`. - pub unsafe extern "C" fn pixel_grid_new(width: usize, height: usize) -> *mut PixelGrid { + #[no_mangle] + pub unsafe extern "C" fn sp2_pixel_grid_new(width: usize, height: usize) -> *mut PixelGrid { Box::into_raw(Box::new(PixelGrid::new(width, height))) } /// Loads a `PixelGrid` with the specified dimensions from the provided data. /// The returned instance has to be freed with `pixel_grid_dealloc`. - pub unsafe extern "C" fn pixel_grid_load(width: usize, height: usize, data: *const u8, data_length: usize) -> *mut PixelGrid { + #[no_mangle] + pub unsafe extern "C" fn sp2_pixel_grid_load(width: usize, height: usize, data: *const u8, data_length: usize) -> *mut PixelGrid { let data = std::slice::from_raw_parts(data, data_length); Box::into_raw(Box::new(PixelGrid::load(width, height, data))) } /// Clones a `PixelGrid`. /// The returned instance has to be freed with `pixel_grid_dealloc`. - pub unsafe extern "C" fn pixel_grid_clone(this: *const PixelGrid) -> *mut PixelGrid { + #[no_mangle] + pub unsafe extern "C" fn sp2_pixel_grid_clone(this: *const PixelGrid) -> *mut PixelGrid { Box::into_raw(Box::new((*this).clone())) } /// Deallocates a `PixelGrid`. /// /// Note: do not call this if the grid has been consumed in another way, e.g. to create a command. - pub unsafe extern "C" fn pixel_grid_dealloc(this: *mut PixelGrid) { + #[no_mangle] + pub unsafe extern "C" fn sp2_pixel_grid_dealloc(this: *mut PixelGrid) { _ = Box::from_raw(this); } /// Get the current value at the specified position - pub unsafe extern "C" fn pixel_grid_get(this: *const PixelGrid, x: usize, y: usize) -> bool { + #[no_mangle] + pub unsafe extern "C" fn sp2_pixel_grid_get(this: *const PixelGrid, x: usize, y: usize) -> bool { (*this).get(x, y) } /// Sets the current value at the specified position - pub unsafe extern "C" fn pixel_grid_set(this: *mut PixelGrid, x: usize, y: usize, value: bool) { + #[no_mangle] + pub unsafe extern "C" fn sp2_pixel_grid_set(this: *mut PixelGrid, x: usize, y: usize, value: bool) { (*this).set(x, y, value); } /// Fills the whole `PixelGrid` with the specified value - pub unsafe extern "C" fn pixel_grid_fill(this: *mut PixelGrid, value: bool) { + #[no_mangle] + pub unsafe extern "C" fn sp2_pixel_grid_fill(this: *mut PixelGrid, value: bool) { (*this).fill(value); } /// Gets the width in pixels of the `PixelGrid` instance. - pub unsafe extern "C" fn pixel_grid_width(this: *const PixelGrid) -> usize { + #[no_mangle] + pub unsafe extern "C" fn sp2_pixel_grid_width(this: *const PixelGrid) -> usize { (*this).width } /// Gets the height in pixels of the `PixelGrid` instance. - pub unsafe extern "C" fn pixel_grid_height(this: *const PixelGrid) -> usize { + #[no_mangle] + pub unsafe extern "C" fn sp2_pixel_grid_height(this: *const PixelGrid) -> usize { (*this).height } }