From 57d9e90b0f1c26652f944173ae800a9b8e43ecf3 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Fri, 11 Apr 2025 21:40:49 +0200 Subject: [PATCH] wip update to next servicepoint version --- Cargo.lock | 9 ++- Cargo.toml | 8 +-- example/main.c | 2 +- include/servicepoint.h | 85 +++++++++++------------- src/bitmap.rs | 56 +++++++++------- src/bitvec.rs | 18 +++--- src/brightness_grid.rs | 36 ++++++----- src/char_grid.rs | 16 ++--- src/command.rs | 143 ++++++++++++++++++++--------------------- src/connection.rs | 51 +++++++-------- src/constants.rs | 2 +- src/cp437_grid.rs | 30 +++++---- src/packet.rs | 21 +++--- 13 files changed, 242 insertions(+), 235 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9fcfa8f..40ece4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,9 +98,9 @@ dependencies = [ [[package]] name = "cbindgen" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb" +checksum = "eadd868a2ce9ca38de7eeafdcec9c7065ef89b42b32f0839278d55f35c54d1ff" dependencies = [ "clap", "heck", @@ -407,9 +407,8 @@ dependencies = [ [[package]] name = "servicepoint" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93b52049be55a15fe37c13249d7f96aa8a5de56e1a41838e74a822ee8316a0c4" +version = "0.13.2" +source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#fe67160974d9fed542eb37e5e9a202eaf6fe00dc" dependencies = [ "bitvec", "bzip2", diff --git a/Cargo.toml b/Cargo.toml index 7750abc..9e52832 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,14 +15,14 @@ keywords = ["cccb", "cccb-servicepoint", "cbindgen"] crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] -cbindgen = "0.27.0" +cbindgen = "0.28.0" -[dependencies.servicepoint] -version = "0.13.1" -features = ["all_compressions"] +[dependencies] +servicepoint = { features = ["all_compressions"], git = "https://git.berlin.ccc.de/servicepoint/servicepoint/", branch = "next" } [lints.rust] missing-docs = "warn" +unsafe_op_in_unsafe_fn = "warn" [package.metadata.docs.rs] all-features = true diff --git a/example/main.c b/example/main.c index 1454804..aeb811b 100644 --- a/example/main.c +++ b/example/main.c @@ -2,7 +2,7 @@ #include "servicepoint.h" int main(void) { - SPConnection *connection = sp_connection_open("localhost:2342"); + SPUdpConnection *connection = sp_connection_open("localhost:2342"); if (connection == NULL) return 1; diff --git a/include/servicepoint.h b/include/servicepoint.h index d9cbe57..e631bc0 100644 --- a/include/servicepoint.h +++ b/include/servicepoint.h @@ -1,4 +1,4 @@ -/* Generated with cbindgen:0.27.0 */ +/* Generated with cbindgen:0.28.0 */ /* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ @@ -168,19 +168,6 @@ typedef struct SPCharGrid SPCharGrid; */ typedef struct SPCommand SPCommand; -/** - * A connection to the display. - * - * # Examples - * - * ```C - * CConnection connection = sp_connection_open("172.23.42.29:2342"); - * if (connection != NULL) - * sp_connection_send_command(connection, sp_command_clear()); - * ``` - */ -typedef struct SPConnection SPConnection; - /** * A C-wrapper for grid containing codepage 437 characters. * @@ -202,6 +189,19 @@ typedef struct SPCp437Grid SPCp437Grid; */ typedef struct SPPacket SPPacket; +/** + * A connection to the display. + * + * # Examples + * + * ```C + * CConnection connection = sp_connection_open("172.23.42.29:2342"); + * if (connection != NULL) + * sp_connection_send_command(connection, sp_command_clear()); + * ``` + */ +typedef struct SPUdpConnection SPUdpConnection; + /** * Represents a span of memory (`&mut [u8]` ) as a struct usable by C code. * @@ -290,7 +290,7 @@ void sp_bitmap_fill(SPBitmap *bitmap, bool value); * * [SPCommand]: [crate::SPCommand] */ -void sp_bitmap_free(SPBitmap *bitmap); +void sp_bitmap_free(SPBitmap **bitmap); /** * Gets the current value at the specified position in the [SPBitmap]. @@ -341,13 +341,18 @@ size_t sp_bitmap_height(const SPBitmap *bitmap); * - `width`: size in pixels in x-direction * - `height`: size in pixels in y-direction * - * returns: [SPBitmap] that contains a copy of the provided data. Will never return NULL. + * returns: [SPBitmap] that contains a copy of the provided data, or NULL in case of an error. + * + * # Errors + * + * In the following cases, this function will return NULL: + * + * - when the dimensions and data size do not match exactly. + * - when the width is not dividable by 8 * * # Panics * * - when `data` is NULL - * - when the dimensions and data size do not match exactly. - * - when the width is not dividable by 8 * * # Safety * @@ -370,9 +375,11 @@ SPBitmap *sp_bitmap_load(size_t width, * - `width`: size in pixels in x-direction * - `height`: size in pixels in y-direction * - * returns: [SPBitmap] initialized to all pixels off. Will never return NULL. + * returns: [SPBitmap] initialized to all pixels off, or NULL in case of an error. * - * # Panics + * # Errors + * + * In the following cases, this function will return NULL: * * - when the width is not dividable by 8 * @@ -1206,7 +1213,7 @@ SPCommand *sp_command_bitmap_linear_or(size_t offset, SPCommand *sp_command_bitmap_linear_win(size_t x, size_t y, SPBitmap *bitmap, - SPCompressionCode compression_code); + SPCompressionCode compression); /** * Set pixel data according to a xor-mask starting at the offset. @@ -1449,21 +1456,7 @@ SPCommand *sp_command_utf8_data(size_t x, SPCharGrid *grid); /** - * Creates a new instance of [SPConnection] for testing that does not actually send anything. - * - * returns: a new instance. Will never return NULL. - * - * # Safety - * - * The caller has to make sure that: - * - * - the returned instance is freed in some way, either by using a consuming function or - * by explicitly calling `sp_connection_free`. - */ -SPConnection *sp_connection_fake(void); - -/** - * Closes and deallocates a [SPConnection]. + * Closes and deallocates a [SPUdpConnection]. * * # Panics * @@ -1473,13 +1466,13 @@ SPConnection *sp_connection_fake(void); * * The caller has to make sure that: * - * - `connection` points to a valid [SPConnection] + * - `connection` points to a valid [SPUdpConnection] * - `connection` is not used concurrently or after this call */ -void sp_connection_free(SPConnection *connection); +void sp_connection_free(SPUdpConnection *connection); /** - * Creates a new instance of [SPConnection]. + * Creates a new instance of [SPUdpConnection]. * * returns: NULL if connection fails, or connected instance * @@ -1494,10 +1487,10 @@ void sp_connection_free(SPConnection *connection); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_connection_free`. */ -SPConnection *sp_connection_open(const char *host); +SPUdpConnection *sp_connection_open(const char *host); /** - * Sends a [SPCommand] to the display using the [SPConnection]. + * Sends a [SPCommand] to the display using the [SPUdpConnection]. * * The passed `command` gets consumed. * @@ -1512,15 +1505,15 @@ SPConnection *sp_connection_open(const char *host); * * The caller has to make sure that: * - * - `connection` points to a valid instance of [SPConnection] + * - `connection` points to a valid instance of [SPUdpConnection] * - `command` points to a valid instance of [SPPacket] * - `command` is not used concurrently or after this call */ -bool sp_connection_send_command(const SPConnection *connection, +bool sp_connection_send_command(const SPUdpConnection *connection, SPCommand *command); /** - * Sends a [SPPacket] to the display using the [SPConnection]. + * Sends a [SPPacket] to the display using the [SPUdpConnection]. * * The passed `packet` gets consumed. * @@ -1535,11 +1528,11 @@ bool sp_connection_send_command(const SPConnection *connection, * * The caller has to make sure that: * - * - `connection` points to a valid instance of [SPConnection] + * - `connection` points to a valid instance of [SPUdpConnection] * - `packet` points to a valid instance of [SPPacket] * - `packet` is not used concurrently or after this call */ -bool sp_connection_send_packet(const SPConnection *connection, +bool sp_connection_send_packet(const SPUdpConnection *connection, SPPacket *packet); /** diff --git a/src/bitmap.rs b/src/bitmap.rs index 3313385..45993d8 100644 --- a/src/bitmap.rs +++ b/src/bitmap.rs @@ -3,7 +3,7 @@ //! prefix `sp_bitmap_` use servicepoint::{DataRef, Grid}; -use std::ptr::NonNull; +use std::ptr::{null_mut, NonNull}; use crate::byte_slice::SPByteSlice; @@ -26,9 +26,11 @@ pub struct SPBitmap(pub(crate) servicepoint::Bitmap); /// - `width`: size in pixels in x-direction /// - `height`: size in pixels in y-direction /// -/// returns: [SPBitmap] initialized to all pixels off. Will never return NULL. +/// returns: [SPBitmap] initialized to all pixels off, or NULL in case of an error. /// -/// # Panics +/// # Errors +/// +/// In the following cases, this function will return NULL: /// /// - when the width is not dividable by 8 /// @@ -42,9 +44,12 @@ pub struct SPBitmap(pub(crate) servicepoint::Bitmap); pub unsafe extern "C" fn sp_bitmap_new( width: usize, height: usize, -) -> NonNull { - let result = Box::new(SPBitmap(servicepoint::Bitmap::new(width, height))); - NonNull::from(Box::leak(result)) +) -> *mut SPBitmap { + if let Some(bitmap) = servicepoint::Bitmap::new(width, height) { + Box::leak(Box::new(SPBitmap(bitmap))) + }else { + std::ptr::null_mut() + } } /// Creates a new [SPBitmap] with a size matching the screen. @@ -70,13 +75,18 @@ pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull { /// - `width`: size in pixels in x-direction /// - `height`: size in pixels in y-direction /// -/// returns: [SPBitmap] that contains a copy of the provided data. Will never return NULL. +/// returns: [SPBitmap] that contains a copy of the provided data, or NULL in case of an error. +/// +/// # Errors +/// +/// In the following cases, this function will return NULL: +/// +/// - when the dimensions and data size do not match exactly. +/// - when the width is not dividable by 8 /// /// # Panics /// /// - when `data` is NULL -/// - when the dimensions and data size do not match exactly. -/// - when the width is not dividable by 8 /// /// # Safety /// @@ -91,12 +101,14 @@ pub unsafe extern "C" fn sp_bitmap_load( height: usize, data: *const u8, data_length: usize, -) -> NonNull { +) -> *mut SPBitmap { assert!(!data.is_null()); - let data = std::slice::from_raw_parts(data, data_length); - let result = - Box::new(SPBitmap(servicepoint::Bitmap::load(width, height, data))); - NonNull::from(Box::leak(result)) + let data = unsafe {std::slice::from_raw_parts(data, data_length)}; + if let Ok(bitmap) = servicepoint::Bitmap::load(width, height, data) { + Box::leak(Box::new(SPBitmap(bitmap))) + }else { + std::ptr::null_mut() + } } /// Clones a [SPBitmap]. @@ -120,7 +132,7 @@ pub unsafe extern "C" fn sp_bitmap_clone( bitmap: *const SPBitmap, ) -> NonNull { assert!(!bitmap.is_null()); - let result = Box::new(SPBitmap((*bitmap).0.clone())); + let result = Box::new(SPBitmap(unsafe {(*bitmap).0.clone()})); NonNull::from(Box::leak(result)) } @@ -142,7 +154,7 @@ pub unsafe extern "C" fn sp_bitmap_clone( #[no_mangle] pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) { assert!(!bitmap.is_null()); - _ = Box::from_raw(bitmap); + _ = unsafe {Box::from_raw(bitmap)}; } /// Gets the current value at the specified position in the [SPBitmap]. @@ -170,7 +182,7 @@ pub unsafe extern "C" fn sp_bitmap_get( y: usize, ) -> bool { assert!(!bitmap.is_null()); - (*bitmap).0.get(x, y) + unsafe {(*bitmap).0.get(x, y)} } /// Sets the value of the specified position in the [SPBitmap]. @@ -202,7 +214,7 @@ pub unsafe extern "C" fn sp_bitmap_set( value: bool, ) { assert!(!bitmap.is_null()); - (*bitmap).0.set(x, y, value); + unsafe {(*bitmap).0.set(x, y, value)}; } /// Sets the state of all pixels in the [SPBitmap]. @@ -225,7 +237,7 @@ pub unsafe extern "C" fn sp_bitmap_set( #[no_mangle] pub unsafe extern "C" fn sp_bitmap_fill(bitmap: *mut SPBitmap, value: bool) { assert!(!bitmap.is_null()); - (*bitmap).0.fill(value); + unsafe {(*bitmap).0.fill(value)}; } /// Gets the width in pixels of the [SPBitmap] instance. @@ -246,7 +258,7 @@ pub unsafe extern "C" fn sp_bitmap_fill(bitmap: *mut SPBitmap, value: bool) { #[no_mangle] pub unsafe extern "C" fn sp_bitmap_width(bitmap: *const SPBitmap) -> usize { assert!(!bitmap.is_null()); - (*bitmap).0.width() + unsafe {(*bitmap).0.width()} } /// Gets the height in pixels of the [SPBitmap] instance. @@ -267,7 +279,7 @@ pub unsafe extern "C" fn sp_bitmap_width(bitmap: *const SPBitmap) -> usize { #[no_mangle] pub unsafe extern "C" fn sp_bitmap_height(bitmap: *const SPBitmap) -> usize { assert!(!bitmap.is_null()); - (*bitmap).0.height() + unsafe {(*bitmap).0.height()} } /// Gets an unsafe reference to the data of the [SPBitmap] instance. @@ -288,7 +300,7 @@ pub unsafe extern "C" fn sp_bitmap_unsafe_data_ref( bitmap: *mut SPBitmap, ) -> SPByteSlice { assert!(!bitmap.is_null()); - let data = (*bitmap).0.data_ref_mut(); + let data = unsafe {(*bitmap).0.data_ref_mut()}; SPByteSlice { start: NonNull::new(data.as_mut_ptr_range().start).unwrap(), length: data.len(), diff --git a/src/bitvec.rs b/src/bitvec.rs index 484e849..ed96be5 100644 --- a/src/bitvec.rs +++ b/src/bitvec.rs @@ -79,7 +79,7 @@ pub unsafe extern "C" fn sp_bitvec_load( data_length: usize, ) -> NonNull { assert!(!data.is_null()); - let data = std::slice::from_raw_parts(data, data_length); + let data = unsafe {std::slice::from_raw_parts(data, data_length)}; let result = Box::new(SPBitVec(servicepoint::BitVec::from_slice(data))); NonNull::from(Box::leak(result)) } @@ -105,7 +105,7 @@ pub unsafe extern "C" fn sp_bitvec_clone( bit_vec: *const SPBitVec, ) -> NonNull { assert!(!bit_vec.is_null()); - let result = Box::new((*bit_vec).clone()); + let result = Box::new(unsafe {(*bit_vec).clone()}); NonNull::from(Box::leak(result)) } @@ -127,7 +127,7 @@ pub unsafe extern "C" fn sp_bitvec_clone( #[no_mangle] pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) { assert!(!bit_vec.is_null()); - _ = Box::from_raw(bit_vec); + _ = unsafe {Box::from_raw(bit_vec)}; } /// Gets the value of a bit from the [SPBitVec]. @@ -156,7 +156,7 @@ pub unsafe extern "C" fn sp_bitvec_get( index: usize, ) -> bool { assert!(!bit_vec.is_null()); - *(*bit_vec).0.get(index).unwrap() + unsafe {*(*bit_vec).0.get(index).unwrap()} } /// Sets the value of a bit in the [SPBitVec]. @@ -185,7 +185,7 @@ pub unsafe extern "C" fn sp_bitvec_set( value: bool, ) { assert!(!bit_vec.is_null()); - (*bit_vec).0.set(index, value) + unsafe {(*bit_vec).0.set(index, value)} } /// Sets the value of all bits in the [SPBitVec]. @@ -208,7 +208,7 @@ pub unsafe extern "C" fn sp_bitvec_set( #[no_mangle] pub unsafe extern "C" fn sp_bitvec_fill(bit_vec: *mut SPBitVec, value: bool) { assert!(!bit_vec.is_null()); - (*bit_vec).0.fill(value) + unsafe {(*bit_vec).0.fill(value)} } /// Gets the length of the [SPBitVec] in bits. @@ -229,7 +229,7 @@ pub unsafe extern "C" fn sp_bitvec_fill(bit_vec: *mut SPBitVec, value: bool) { #[no_mangle] pub unsafe extern "C" fn sp_bitvec_len(bit_vec: *const SPBitVec) -> usize { assert!(!bit_vec.is_null()); - (*bit_vec).0.len() + unsafe {(*bit_vec).0.len()} } /// Returns true if length is 0. @@ -250,7 +250,7 @@ pub unsafe extern "C" fn sp_bitvec_len(bit_vec: *const SPBitVec) -> usize { #[no_mangle] pub unsafe extern "C" fn sp_bitvec_is_empty(bit_vec: *const SPBitVec) -> bool { assert!(!bit_vec.is_null()); - (*bit_vec).0.is_empty() + unsafe {(*bit_vec).0.is_empty()} } /// Gets an unsafe reference to the data of the [SPBitVec] instance. @@ -275,7 +275,7 @@ pub unsafe extern "C" fn sp_bitvec_unsafe_data_ref( bit_vec: *mut SPBitVec, ) -> SPByteSlice { assert!(!bit_vec.is_null()); - let data = (*bit_vec).0.as_raw_mut_slice(); + let data = unsafe {(*bit_vec).0.as_raw_mut_slice()}; SPByteSlice { start: NonNull::new(data.as_mut_ptr_range().start).unwrap(), length: data.len(), diff --git a/src/brightness_grid.rs b/src/brightness_grid.rs index 83af008..cfd2589 100644 --- a/src/brightness_grid.rs +++ b/src/brightness_grid.rs @@ -77,14 +77,18 @@ pub unsafe extern "C" fn sp_brightness_grid_load( height: usize, data: *const u8, data_length: usize, -) -> NonNull { +) -> *mut SPBrightnessGrid { assert!(!data.is_null()); - let data = std::slice::from_raw_parts(data, data_length); - let grid = servicepoint::ByteGrid::load(width, height, data); - let grid = servicepoint::BrightnessGrid::try_from(grid) - .expect("invalid brightness value"); - let result = Box::new(SPBrightnessGrid(grid)); - NonNull::from(Box::leak(result)) + let data =unsafe { std::slice::from_raw_parts(data, data_length)}; + let grid = match servicepoint::ByteGrid::load(width, height, data) { + None => return std::ptr::null_mut(), + Some(grid) => grid + }; + if let Ok(grid )= servicepoint::BrightnessGrid::try_from(grid) { + Box::leak(Box::new(SPBrightnessGrid(grid))) + }else { + std::ptr::null_mut() + } } /// Clones a [SPBrightnessGrid]. @@ -112,7 +116,7 @@ pub unsafe extern "C" fn sp_brightness_grid_clone( brightness_grid: *const SPBrightnessGrid, ) -> NonNull { assert!(!brightness_grid.is_null()); - let result = Box::new((*brightness_grid).clone()); + let result = Box::new(unsafe {(*brightness_grid).clone()}); NonNull::from(Box::leak(result)) } @@ -140,7 +144,7 @@ pub unsafe extern "C" fn sp_brightness_grid_free( brightness_grid: *mut SPBrightnessGrid, ) { assert!(!brightness_grid.is_null()); - _ = Box::from_raw(brightness_grid); + _ = unsafe {Box::from_raw(brightness_grid)}; } /// Gets the current value at the specified position. @@ -170,7 +174,7 @@ pub unsafe extern "C" fn sp_brightness_grid_get( y: usize, ) -> u8 { assert!(!brightness_grid.is_null()); - (*brightness_grid).0.get(x, y).into() + unsafe {(*brightness_grid).0.get(x, y)}.into() } /// Sets the value of the specified position in the [SPBrightnessGrid]. @@ -205,7 +209,7 @@ pub unsafe extern "C" fn sp_brightness_grid_set( assert!(!brightness_grid.is_null()); let brightness = servicepoint::Brightness::try_from(value) .expect("invalid brightness value"); - (*brightness_grid).0.set(x, y, brightness); + unsafe {(*brightness_grid).0.set(x, y, brightness)}; } /// Sets the value of all cells in the [SPBrightnessGrid]. @@ -234,7 +238,7 @@ pub unsafe extern "C" fn sp_brightness_grid_fill( assert!(!brightness_grid.is_null()); let brightness = servicepoint::Brightness::try_from(value) .expect("invalid brightness value"); - (*brightness_grid).0.fill(brightness); + unsafe {(*brightness_grid).0.fill(brightness)}; } /// Gets the width of the [SPBrightnessGrid] instance. @@ -259,7 +263,7 @@ pub unsafe extern "C" fn sp_brightness_grid_width( brightness_grid: *const SPBrightnessGrid, ) -> usize { assert!(!brightness_grid.is_null()); - (*brightness_grid).0.width() + unsafe {(*brightness_grid).0.width()} } /// Gets the height of the [SPBrightnessGrid] instance. @@ -284,7 +288,7 @@ pub unsafe extern "C" fn sp_brightness_grid_height( brightness_grid: *const SPBrightnessGrid, ) -> usize { assert!(!brightness_grid.is_null()); - (*brightness_grid).0.height() + unsafe {(*brightness_grid).0.height()} } /// Gets an unsafe reference to the data of the [SPBrightnessGrid] instance. @@ -312,9 +316,9 @@ pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref( ) -> SPByteSlice { assert!(!brightness_grid.is_null()); assert_eq!(core::mem::size_of::(), 1); - let data = (*brightness_grid).0.data_ref_mut(); + let data = unsafe {(*brightness_grid).0.data_ref_mut()}; // this assumes more about the memory layout than rust guarantees. yikes! - let data: &mut [u8] = transmute(data); + let data: &mut [u8] = unsafe {transmute(data)}; SPByteSlice { start: NonNull::new(data.as_mut_ptr_range().start).unwrap(), length: data.len(), diff --git a/src/char_grid.rs b/src/char_grid.rs index dfaf225..3c51e89 100644 --- a/src/char_grid.rs +++ b/src/char_grid.rs @@ -74,7 +74,7 @@ pub unsafe extern "C" fn sp_char_grid_load( data_length: usize, ) -> NonNull { assert!(data.is_null()); - let data = std::slice::from_raw_parts(data, data_length); + let data = unsafe {std::slice::from_raw_parts(data, data_length)}; let result = Box::new(SPCharGrid( servicepoint::CharGrid::load_utf8(width, height, data.to_vec()) .unwrap(), @@ -103,7 +103,7 @@ pub unsafe extern "C" fn sp_char_grid_clone( char_grid: *const SPCharGrid, ) -> NonNull { assert!(!char_grid.is_null()); - let result = Box::new((*char_grid).clone()); + let result = Box::new(unsafe{(*char_grid).clone()}); NonNull::from(Box::leak(result)) } @@ -125,7 +125,7 @@ pub unsafe extern "C" fn sp_char_grid_clone( #[no_mangle] pub unsafe extern "C" fn sp_char_grid_free(char_grid: *mut SPCharGrid) { assert!(!char_grid.is_null()); - _ = Box::from_raw(char_grid); + _ = unsafe {Box::from_raw(char_grid)}; } /// Gets the current value at the specified position. @@ -153,7 +153,7 @@ pub unsafe extern "C" fn sp_char_grid_get( y: usize, ) -> u32 { assert!(!char_grid.is_null()); - (*char_grid).0.get(x, y) as u32 + unsafe {(*char_grid).0.get(x, y) as u32} } /// Sets the value of the specified position in the [SPCharGrid]. @@ -187,7 +187,7 @@ pub unsafe extern "C" fn sp_char_grid_set( value: u32, ) { assert!(!char_grid.is_null()); - (*char_grid).0.set(x, y, char::from_u32(value).unwrap()); + unsafe {(*char_grid).0.set(x, y, char::from_u32(value).unwrap())}; } /// Sets the value of all cells in the [SPCharGrid]. @@ -213,7 +213,7 @@ pub unsafe extern "C" fn sp_char_grid_fill( value: u32, ) { assert!(!char_grid.is_null()); - (*char_grid).0.fill(char::from_u32(value).unwrap()); + unsafe {(*char_grid).0.fill(char::from_u32(value).unwrap())}; } /// Gets the width of the [SPCharGrid] instance. @@ -236,7 +236,7 @@ pub unsafe extern "C" fn sp_char_grid_width( char_grid: *const SPCharGrid, ) -> usize { assert!(!char_grid.is_null()); - (*char_grid).0.width() + unsafe {(*char_grid).0.width()} } /// Gets the height of the [SPCharGrid] instance. @@ -259,5 +259,5 @@ pub unsafe extern "C" fn sp_char_grid_height( char_grid: *const SPCharGrid, ) -> usize { assert!(!char_grid.is_null()); - (*char_grid).0.height() + unsafe {(*char_grid).0.height()} } diff --git a/src/command.rs b/src/command.rs index f7e50ea..0720db6 100644 --- a/src/command.rs +++ b/src/command.rs @@ -2,12 +2,12 @@ //! //! prefix `sp_command_` -use std::ptr::{null_mut, NonNull}; - use crate::{ SPBitVec, SPBitmap, SPBrightnessGrid, SPCharGrid, SPCompressionCode, SPCp437Grid, SPPacket, }; +use servicepoint::{BinaryOperation, GlobalBrightnessCommand}; +use std::ptr::NonNull; /// A low-level display command. /// @@ -23,7 +23,7 @@ use crate::{ /// ``` /// /// [SPConnection]: [crate::SPConnection] -pub struct SPCommand(pub(crate) servicepoint::Command); +pub struct SPCommand(pub(crate) servicepoint::TypedCommand); impl Clone for SPCommand { fn clone(&self) -> Self { @@ -54,9 +54,9 @@ impl Clone for SPCommand { pub unsafe extern "C" fn sp_command_try_from_packet( packet: *mut SPPacket, ) -> *mut SPCommand { - let packet = *Box::from_raw(packet); - match servicepoint::Command::try_from(packet.0) { - Err(_) => null_mut(), + let packet = *unsafe{Box::from_raw(packet)}; + match servicepoint::TypedCommand::try_from(packet.0) { + Err(_) => std::ptr::null_mut(), Ok(command) => Box::into_raw(Box::new(SPCommand(command))), } } @@ -82,7 +82,7 @@ pub unsafe extern "C" fn sp_command_clone( command: *const SPCommand, ) -> NonNull { assert!(!command.is_null()); - let result = Box::new((*command).clone()); + let result = Box::new(unsafe { (*command).clone() }); NonNull::from(Box::leak(result)) } @@ -106,7 +106,7 @@ pub unsafe extern "C" fn sp_command_clone( /// by explicitly calling `sp_command_free`. #[no_mangle] pub unsafe extern "C" fn sp_command_clear() -> NonNull { - let result = Box::new(SPCommand(servicepoint::Command::Clear)); + let result = Box::new(SPCommand(servicepoint::ClearCommand.into())); NonNull::from(Box::leak(result)) } @@ -124,7 +124,7 @@ pub unsafe extern "C" fn sp_command_clear() -> NonNull { /// by explicitly calling `sp_command_free`. #[no_mangle] pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull { - let result = Box::new(SPCommand(servicepoint::Command::HardReset)); + let result = Box::new(SPCommand(servicepoint::HardResetCommand.into())); NonNull::from(Box::leak(result)) } @@ -140,7 +140,7 @@ pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull { /// by explicitly calling `sp_command_free`. #[no_mangle] pub unsafe extern "C" fn sp_command_fade_out() -> NonNull { - let result = Box::new(SPCommand(servicepoint::Command::FadeOut)); + let result = Box::new(SPCommand(servicepoint::FadeOutCommand.into())); NonNull::from(Box::leak(result)) } @@ -164,8 +164,7 @@ pub unsafe extern "C" fn sp_command_brightness( ) -> NonNull { let brightness = servicepoint::Brightness::try_from(brightness) .expect("invalid brightness"); - let result = - Box::new(SPCommand(servicepoint::Command::Brightness(brightness))); + let result = Box::new(SPCommand(GlobalBrightnessCommand::from(brightness).into())); NonNull::from(Box::leak(result)) } @@ -194,11 +193,11 @@ pub unsafe extern "C" fn sp_command_char_brightness( grid: *mut SPBrightnessGrid, ) -> NonNull { assert!(!grid.is_null()); - let byte_grid = *Box::from_raw(grid); - let result = Box::new(SPCommand(servicepoint::Command::CharBrightness( - servicepoint::Origin::new(x, y), - byte_grid.0, - ))); + let byte_grid = unsafe { *Box::from_raw(grid) }; + let result = Box::new(SPCommand(servicepoint::BrightnessGridCommand { + origin: servicepoint::Origin::new(x, y), + grid: byte_grid.0, + }.into())); NonNull::from(Box::leak(result)) } @@ -232,15 +231,8 @@ pub unsafe extern "C" fn sp_command_bitmap_linear( offset: usize, bit_vec: *mut SPBitVec, compression: SPCompressionCode, -) -> NonNull { - assert!(!bit_vec.is_null()); - let bit_vec = *Box::from_raw(bit_vec); - let result = Box::new(SPCommand(servicepoint::Command::BitmapLinear( - offset, - bit_vec.into(), - compression.try_into().expect("invalid compression code"), - ))); - NonNull::from(Box::leak(result)) +) -> *mut SPCommand { + unsafe {sp_command_bitmap_linear_internal(offset, bit_vec, compression, BinaryOperation::Overwrite)} } /// Set pixel data according to an and-mask starting at the offset. @@ -273,15 +265,8 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_and( offset: usize, bit_vec: *mut SPBitVec, compression: SPCompressionCode, -) -> NonNull { - assert!(!bit_vec.is_null()); - let bit_vec = *Box::from_raw(bit_vec); - let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearAnd( - offset, - bit_vec.into(), - compression.try_into().expect("invalid compression code"), - ))); - NonNull::from(Box::leak(result)) +) -> *mut SPCommand { + unsafe {sp_command_bitmap_linear_internal(offset, bit_vec, compression, BinaryOperation::Xor)} } /// Set pixel data according to an or-mask starting at the offset. @@ -314,15 +299,8 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_or( offset: usize, bit_vec: *mut SPBitVec, compression: SPCompressionCode, -) -> NonNull { - assert!(!bit_vec.is_null()); - let bit_vec = *Box::from_raw(bit_vec); - let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearOr( - offset, - bit_vec.into(), - compression.try_into().expect("invalid compression code"), - ))); - NonNull::from(Box::leak(result)) +) -> *mut SPCommand { + unsafe {sp_command_bitmap_linear_internal(offset, bit_vec, compression, BinaryOperation::Or)} } /// Set pixel data according to a xor-mask starting at the offset. @@ -355,15 +333,30 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_xor( offset: usize, bit_vec: *mut SPBitVec, compression: SPCompressionCode, -) -> NonNull { +) -> *mut SPCommand { + unsafe {sp_command_bitmap_linear_internal(offset, bit_vec, compression, BinaryOperation::Xor)} +} + +#[inline] +unsafe fn sp_command_bitmap_linear_internal( + offset: usize, + bit_vec: *mut SPBitVec, + compression: SPCompressionCode, + operation: BinaryOperation +) -> *mut SPCommand { assert!(!bit_vec.is_null()); - let bit_vec = *Box::from_raw(bit_vec); - let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearXor( + let bit_vec = unsafe { *Box::from_raw(bit_vec) }; + let compression = match compression.try_into() { + Ok(compression) => compression, + Err(_) => return std::ptr::null_mut(), + }; + let command = SPCommand(servicepoint::BitVecCommand { offset, - bit_vec.into(), - compression.try_into().expect("invalid compression code"), - ))); - NonNull::from(Box::leak(result)) + operation, + bitvec: bit_vec.into(), + compression, + }.into()); + Box::leak(Box::new(command)) } /// Show codepage 437 encoded text on the screen. @@ -391,11 +384,12 @@ pub unsafe extern "C" fn sp_command_cp437_data( grid: *mut SPCp437Grid, ) -> NonNull { assert!(!grid.is_null()); - let grid = *Box::from_raw(grid); - let result = Box::new(SPCommand(servicepoint::Command::Cp437Data( - servicepoint::Origin::new(x, y), - grid.0, - ))); + let grid = *unsafe{Box::from_raw(grid)}; + let result = Box::new(SPCommand(servicepoint::Cp437GridCommand { + origin: servicepoint::Origin::new(x, + y), + grid: grid.0, + }.into())); NonNull::from(Box::leak(result)) } @@ -424,11 +418,12 @@ pub unsafe extern "C" fn sp_command_utf8_data( grid: *mut SPCharGrid, ) -> NonNull { assert!(!grid.is_null()); - let grid = *Box::from_raw(grid); - let result = Box::new(SPCommand(servicepoint::Command::Utf8Data( - servicepoint::Origin::new(x, y), - grid.0, - ))); + let grid = unsafe { *Box::from_raw(grid) }; + let result = Box::new(SPCommand(servicepoint::CharGridCommand { + origin: servicepoint::Origin::new(x, + y), + grid: grid.0, + }.into())); NonNull::from(Box::leak(result)) } @@ -457,18 +452,20 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_win( x: usize, y: usize, bitmap: *mut SPBitmap, - compression_code: SPCompressionCode, -) -> NonNull { + compression: SPCompressionCode, +) -> *mut SPCommand { assert!(!bitmap.is_null()); - let byte_grid = (*Box::from_raw(bitmap)).0; - let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearWin( - servicepoint::Origin::new(x, y), - byte_grid, - compression_code - .try_into() - .expect("invalid compression code"), - ))); - NonNull::from(Box::leak(result)) + let bitmap = unsafe { *Box::from_raw(bitmap) }.0; + let compression = match compression.try_into() { + Ok(compression) => compression, + Err(_) => return std::ptr::null_mut(), + }; + let command = SPCommand(servicepoint::BitmapCommand { + origin: servicepoint::Origin::new(x, y), + bitmap, + compression, + }.into()); + Box::leak(Box::new(command)) } /// Deallocates a [SPCommand]. @@ -494,5 +491,5 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_win( #[no_mangle] pub unsafe extern "C" fn sp_command_free(command: *mut SPCommand) { assert!(!command.is_null()); - _ = Box::from_raw(command); + _ = unsafe { Box::from_raw(command) }; } diff --git a/src/connection.rs b/src/connection.rs index 8b31243..6bbdbe2 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -3,8 +3,7 @@ //! prefix `sp_connection_` use std::ffi::{c_char, CStr}; -use std::ptr::{null_mut, NonNull}; - +use servicepoint::Connection; use crate::{SPCommand, SPPacket}; /// A connection to the display. @@ -16,7 +15,7 @@ use crate::{SPCommand, SPPacket}; /// if (connection != NULL) /// sp_connection_send_command(connection, sp_command_clear()); /// ``` -pub struct SPConnection(pub(crate) servicepoint::Connection); +pub struct SPConnection(pub(crate) servicepoint::UdpConnection); /// Creates a new instance of [SPConnection]. /// @@ -37,30 +36,30 @@ pub unsafe extern "C" fn sp_connection_open( host: *const c_char, ) -> *mut SPConnection { assert!(!host.is_null()); - let host = CStr::from_ptr(host).to_str().expect("Bad encoding"); - let connection = match servicepoint::Connection::open(host) { - Err(_) => return null_mut(), + let host = unsafe {CStr::from_ptr(host)}.to_str().expect("Bad encoding"); + let connection = match servicepoint::UdpConnection::open(host) { + Err(_) => return std::ptr::null_mut(), Ok(value) => value, }; Box::into_raw(Box::new(SPConnection(connection))) } -/// Creates a new instance of [SPConnection] for testing that does not actually send anything. -/// -/// returns: a new instance. Will never return NULL. -/// -/// # Safety -/// -/// The caller has to make sure that: -/// -/// - the returned instance is freed in some way, either by using a consuming function or -/// by explicitly calling `sp_connection_free`. -#[no_mangle] -pub unsafe extern "C" fn sp_connection_fake() -> NonNull { - let result = Box::new(SPConnection(servicepoint::Connection::Fake)); - NonNull::from(Box::leak(result)) -} +// /// Creates a new instance of [SPUdpConnection] for testing that does not actually send anything. +// /// +// /// returns: a new instance. Will never return NULL. +// /// +// /// # Safety +// /// +// /// The caller has to make sure that: +// /// +// /// - the returned instance is freed in some way, either by using a consuming function or +// /// by explicitly calling `sp_connection_free`. +// #[no_mangle] +// pub unsafe extern "C" fn sp_connection_fake() -> NonNull { +// let result = Box::new(SPUdpConnection(servicepoint::Connection::Fake)); +// NonNull::from(Box::leak(result)) +// } /// Sends a [SPPacket] to the display using the [SPConnection]. /// @@ -87,8 +86,8 @@ pub unsafe extern "C" fn sp_connection_send_packet( ) -> bool { assert!(!connection.is_null()); assert!(!packet.is_null()); - let packet = Box::from_raw(packet); - (*connection).0.send((*packet).0).is_ok() + let packet = unsafe {Box::from_raw(packet)}; + unsafe {(*connection).0.send((*packet).0)}.is_ok() } /// Sends a [SPCommand] to the display using the [SPConnection]. @@ -116,8 +115,8 @@ pub unsafe extern "C" fn sp_connection_send_command( ) -> bool { assert!(!connection.is_null()); assert!(!command.is_null()); - let command = (*Box::from_raw(command)).0; - (*connection).0.send(command).is_ok() + let command = (*unsafe {Box::from_raw(command)}).0; + unsafe{(*connection).0.send(command)}.is_ok() } /// Closes and deallocates a [SPConnection]. @@ -135,5 +134,5 @@ pub unsafe extern "C" fn sp_connection_send_command( #[no_mangle] pub unsafe extern "C" fn sp_connection_free(connection: *mut SPConnection) { assert!(!connection.is_null()); - _ = Box::from_raw(connection); + _ = unsafe {Box::from_raw(connection)}; } diff --git a/src/constants.rs b/src/constants.rs index 1a268f4..ed4e52d 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -43,6 +43,6 @@ impl TryFrom for CompressionCode { type Error = (); fn try_from(value: SPCompressionCode) -> Result { - CompressionCode::try_from(value as u16) + CompressionCode::try_from(value as u16).map_err(|_|()) } } diff --git a/src/cp437_grid.rs b/src/cp437_grid.rs index 9b366c8..712034c 100644 --- a/src/cp437_grid.rs +++ b/src/cp437_grid.rs @@ -69,13 +69,15 @@ pub unsafe extern "C" fn sp_cp437_grid_load( height: usize, data: *const u8, data_length: usize, -) -> NonNull { +) -> *mut SPCp437Grid { assert!(data.is_null()); - let data = std::slice::from_raw_parts(data, data_length); - let result = Box::new(SPCp437Grid(servicepoint::Cp437Grid::load( - width, height, data, - ))); - NonNull::from(Box::leak(result)) + let data = unsafe{std::slice::from_raw_parts(data, data_length)}; + let grid = servicepoint::Cp437Grid::load( width, height, data, ); + if let Some(grid ) = grid { + Box::leak(Box::new(SPCp437Grid(grid))) + } else { + std::ptr::null_mut() + } } /// Clones a [SPCp437Grid]. @@ -99,7 +101,7 @@ pub unsafe extern "C" fn sp_cp437_grid_clone( cp437_grid: *const SPCp437Grid, ) -> NonNull { assert!(!cp437_grid.is_null()); - let result = Box::new((*cp437_grid).clone()); + let result = Box::new(unsafe {(*cp437_grid).clone()}); NonNull::from(Box::leak(result)) } @@ -121,7 +123,7 @@ pub unsafe extern "C" fn sp_cp437_grid_clone( #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) { assert!(!cp437_grid.is_null()); - _ = Box::from_raw(cp437_grid); + _ = unsafe {Box::from_raw(cp437_grid)}; } /// Gets the current value at the specified position. @@ -149,7 +151,7 @@ pub unsafe extern "C" fn sp_cp437_grid_get( y: usize, ) -> u8 { assert!(!cp437_grid.is_null()); - (*cp437_grid).0.get(x, y) + unsafe{(*cp437_grid).0.get(x, y)} } /// Sets the value of the specified position in the [SPCp437Grid]. @@ -183,7 +185,7 @@ pub unsafe extern "C" fn sp_cp437_grid_set( value: u8, ) { assert!(!cp437_grid.is_null()); - (*cp437_grid).0.set(x, y, value); + unsafe {(*cp437_grid).0.set(x, y, value)}; } /// Sets the value of all cells in the [SPCp437Grid]. @@ -209,7 +211,7 @@ pub unsafe extern "C" fn sp_cp437_grid_fill( value: u8, ) { assert!(!cp437_grid.is_null()); - (*cp437_grid).0.fill(value); + unsafe {(*cp437_grid).0.fill(value)}; } /// Gets the width of the [SPCp437Grid] instance. @@ -232,7 +234,7 @@ pub unsafe extern "C" fn sp_cp437_grid_width( cp437_grid: *const SPCp437Grid, ) -> usize { assert!(!cp437_grid.is_null()); - (*cp437_grid).0.width() + unsafe {(*cp437_grid).0.width()} } /// Gets the height of the [SPCp437Grid] instance. @@ -255,7 +257,7 @@ pub unsafe extern "C" fn sp_cp437_grid_height( cp437_grid: *const SPCp437Grid, ) -> usize { assert!(!cp437_grid.is_null()); - (*cp437_grid).0.height() + unsafe {(*cp437_grid).0.height()} } /// Gets an unsafe reference to the data of the [SPCp437Grid] instance. @@ -277,7 +279,7 @@ pub unsafe extern "C" fn sp_cp437_grid_height( pub unsafe extern "C" fn sp_cp437_grid_unsafe_data_ref( cp437_grid: *mut SPCp437Grid, ) -> SPByteSlice { - let data = (*cp437_grid).0.data_ref_mut(); + let data = unsafe {(*cp437_grid).0.data_ref_mut()}; SPByteSlice { start: NonNull::new(data.as_mut_ptr_range().start).unwrap(), length: data.len(), diff --git a/src/packet.rs b/src/packet.rs index 9293a8a..12afb34 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -2,7 +2,7 @@ //! //! prefix `sp_packet_` -use std::ptr::{null_mut, NonNull}; +use std::ptr::{NonNull}; use crate::SPCommand; @@ -29,11 +29,12 @@ pub struct SPPacket(pub(crate) servicepoint::Packet); #[no_mangle] pub unsafe extern "C" fn sp_packet_from_command( command: *mut SPCommand, -) -> NonNull { +) -> *mut SPPacket { assert!(!command.is_null()); - let command = *Box::from_raw(command); - let result = Box::new(SPPacket(command.0.into())); - NonNull::from(Box::leak(result)) + let command = unsafe {*Box::from_raw(command)}; + if let Ok(packet) = command.0.try_into() { + Box::leak(Box::new(SPPacket(packet))) + } else { std::ptr::null_mut() } } /// Tries to load a [SPPacket] from the passed array with the specified length. @@ -58,9 +59,9 @@ pub unsafe extern "C" fn sp_packet_try_load( length: usize, ) -> *mut SPPacket { assert!(!data.is_null()); - let data = std::slice::from_raw_parts(data, length); + let data = unsafe {std::slice::from_raw_parts(data, length)}; match servicepoint::Packet::try_from(data) { - Err(_) => null_mut(), + Err(_) => std::ptr::null_mut(), Ok(packet) => Box::into_raw(Box::new(SPPacket(packet))), } } @@ -104,7 +105,7 @@ pub unsafe extern "C" fn sp_packet_from_parts( let payload = if payload.is_null() { vec![] } else { - let payload = std::slice::from_raw_parts(payload, payload_len); + let payload = unsafe {std::slice::from_raw_parts(payload, payload_len) }; Vec::from(payload) }; @@ -143,7 +144,7 @@ pub unsafe extern "C" fn sp_packet_clone( packet: *const SPPacket, ) -> NonNull { assert!(!packet.is_null()); - let result = Box::new(SPPacket((*packet).0.clone())); + let result = Box::new(SPPacket(unsafe {(*packet).0.clone()})); NonNull::from(Box::leak(result)) } @@ -162,5 +163,5 @@ pub unsafe extern "C" fn sp_packet_clone( #[no_mangle] pub unsafe extern "C" fn sp_packet_free(packet: *mut SPPacket) { assert!(!packet.is_null()); - _ = Box::from_raw(packet) + _ = unsafe {Box::from_raw(packet)} }