diff --git a/Cargo.lock b/Cargo.lock index c0b11c4..40ece4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "adler2" @@ -408,7 +408,7 @@ dependencies = [ [[package]] name = "servicepoint" version = "0.13.2" -source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#971bee5065139f220022e8108cfaa9c263b8a8a0" +source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#fe67160974d9fed542eb37e5e9a202eaf6fe00dc" dependencies = [ "bitvec", "bzip2", diff --git a/build.rs b/build.rs index 83e9641..93bf703 100644 --- a/build.rs +++ b/build.rs @@ -6,30 +6,28 @@ use std::{env, fs::copy}; +use cbindgen::{generate_with_config, Config}; + fn main() { let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); println!("cargo::rerun-if-changed={crate_dir}"); let config = - cbindgen::Config::from_file(crate_dir.clone() + "/cbindgen.toml") - .unwrap(); + Config::from_file(crate_dir.clone() + "/cbindgen.toml").unwrap(); let output_dir = env::var("OUT_DIR").unwrap(); let header_file = output_dir.clone() + "/servicepoint.h"; - if let Ok(bindings) = cbindgen::generate_with_config(crate_dir, config) { - bindings.write_to_file(&header_file); + generate_with_config(crate_dir, config) + .unwrap() + .write_to_file(&header_file); + println!("cargo:include={output_dir}"); - println!("cargo:include={output_dir}"); - - println!("cargo::rerun-if-env-changed=SERVICEPOINT_HEADER_OUT"); - if let Ok(header_out) = env::var("SERVICEPOINT_HEADER_OUT") { - let header_copy = header_out + "/servicepoint.h"; - println!("cargo:warning=Copying header to {header_copy}"); - copy(header_file, &header_copy).unwrap(); - println!("cargo::rerun-if-changed={header_copy}"); - } - } else { - eprintln!("cargo:warning=Servicepoint header could not be generated"); + println!("cargo::rerun-if-env-changed=SERVICEPOINT_HEADER_OUT"); + if let Ok(header_out) = env::var("SERVICEPOINT_HEADER_OUT") { + let header_copy = header_out + "/servicepoint.h"; + println!("cargo:warning=Copying header to {header_copy}"); + copy(header_file, &header_copy).unwrap(); + println!("cargo::rerun-if-changed={header_copy}"); } } diff --git a/cbindgen.toml b/cbindgen.toml index 48ef574..bf2377c 100644 --- a/cbindgen.toml +++ b/cbindgen.toml @@ -19,13 +19,11 @@ line_endings = "LF" style = "type" usize_is_size_t = true -# this is needed because otherwise the order in the C bindings is different on different machines +# this is needed because otherwise the order in the C# bindings is different on different machines sort_by = "Name" [parse] -parse_deps = true -include = ["servicepoint"] -extra_bindings = ["servicepoint"] +parse_deps = false [parse.expand] features = ["full"] @@ -34,11 +32,5 @@ features = ["full"] include = [] exclude = [] -[export.rename] -"TypedCommand" = "Command" - [enum] rename_variants = "QualifiedScreamingSnakeCase" - -[ptr] -non_null_attribute = "/*notnull*/" diff --git a/examples/lang_c/Cargo.lock b/examples/lang_c/Cargo.lock index 1cd1a29..9435574 100644 --- a/examples/lang_c/Cargo.lock +++ b/examples/lang_c/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "adler2" @@ -423,7 +423,7 @@ dependencies = [ [[package]] name = "servicepoint" version = "0.13.2" -source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#971bee5065139f220022e8108cfaa9c263b8a8a0" +source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#75d24f658764dea251e28c7067446f3ccfbb89b0" dependencies = [ "bitvec", "bzip2", diff --git a/examples/lang_c/Makefile b/examples/lang_c/Makefile index aa31733..1be4009 100644 --- a/examples/lang_c/Makefile +++ b/examples/lang_c/Makefile @@ -36,7 +36,7 @@ CCFLAGS := -static -Os \ -fvisibility=hidden \ -Bsymbolic \ -Wl,--exclude-libs,ALL \ - -fno-ident + -fno-ident \ #-fuse-ld=gold \ -fno-exceptions #-Wl,--icf=all \ diff --git a/examples/lang_c/include/servicepoint.h b/examples/lang_c/include/servicepoint.h index 4a0af95..ca235ca 100644 --- a/examples/lang_c/include/servicepoint.h +++ b/examples/lang_c/include/servicepoint.h @@ -8,35 +8,6 @@ #include #include -/** - * pixel count on whole screen - */ -#define PIXEL_COUNT (PIXEL_WIDTH * PIXEL_HEIGHT) - -/** - * Display height in pixels - * - * # Examples - * - * ```rust - * # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, Bitmap}; - * let grid = Bitmap::new(PIXEL_WIDTH, PIXEL_HEIGHT); - * ``` - */ -#define PIXEL_HEIGHT (TILE_HEIGHT * TILE_SIZE) - -/** - * Display width in pixels - * - * # Examples - * - * ```rust - * # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, Bitmap}; - * let grid = Bitmap::new(PIXEL_WIDTH, PIXEL_HEIGHT); - * ``` - */ -#define PIXEL_WIDTH (TILE_WIDTH * TILE_SIZE) - /** * Count of possible brightness values */ @@ -53,59 +24,39 @@ #define SP_BRIGHTNESS_MIN 0 /** - * Display tile count in the y-direction - * - * # Examples - * - * ```rust - * # use servicepoint::{Cp437Grid, TILE_HEIGHT, TILE_WIDTH}; - * let grid = Cp437Grid::new(TILE_WIDTH, TILE_HEIGHT); - * ``` + * pixel count on whole screen */ -#define TILE_HEIGHT 20 +#define SP_PIXEL_COUNT (SP_PIXEL_WIDTH * SP_PIXEL_HEIGHT) + +/** + * Display height in pixels + */ +#define SP_PIXEL_HEIGHT (SP_TILE_HEIGHT * SP_TILE_SIZE) + +/** + * Display width in pixels + */ +#define SP_PIXEL_WIDTH (SP_TILE_WIDTH * SP_TILE_SIZE) + +/** + * Display tile count in the y-direction + */ +#define SP_TILE_HEIGHT 20 /** * size of a single tile in one dimension */ -#define TILE_SIZE 8 +#define SP_TILE_SIZE 8 /** * Display tile count in the x-direction - * - * # Examples - * - * ```rust - * # use servicepoint::{Cp437Grid, TILE_HEIGHT, TILE_WIDTH}; - * let grid = Cp437Grid::new(TILE_WIDTH, TILE_HEIGHT); - * ``` */ -#define TILE_WIDTH 56 +#define SP_TILE_WIDTH 56 /** - * Specifies the kind of compression to use. Availability depends on features. - * - * # Examples - * - * ```rust - * # use servicepoint::*; - * // create command without payload compression - * # let pixels = Bitmap::max_sized(); - * _ = BitmapCommand { - * origin: Origin::ZERO, - * bitmap: pixels, - * compression: CompressionCode::Uncompressed - * }; - * - * // create command with payload compressed with lzma and appropriate header flags - * # let pixels = Bitmap::max_sized(); - * _ = BitmapCommand { - * origin: Origin::ZERO, - * bitmap: pixels, - * compression: CompressionCode::Lzma - * }; - * ``` + * Specifies the kind of compression to use. */ -enum CompressionCode +enum SPCompressionCode #ifdef __cplusplus : uint16_t #endif // __cplusplus @@ -113,54 +64,28 @@ enum CompressionCode /** * no compression */ - COMPRESSION_CODE_UNCOMPRESSED = 0, + SP_COMPRESSION_CODE_UNCOMPRESSED = 0, /** * compress using flate2 with zlib header */ - COMPRESSION_CODE_ZLIB = 26490, + SP_COMPRESSION_CODE_ZLIB = 26490, /** * compress using bzip2 */ - COMPRESSION_CODE_BZIP2 = 25210, + SP_COMPRESSION_CODE_BZIP2 = 25210, /** * compress using lzma */ - COMPRESSION_CODE_LZMA = 27770, + SP_COMPRESSION_CODE_LZMA = 27770, /** * compress using Zstandard */ - COMPRESSION_CODE_ZSTD = 31347, + SP_COMPRESSION_CODE_ZSTD = 31347, }; #ifndef __cplusplus -typedef uint16_t CompressionCode; +typedef uint16_t SPCompressionCode; #endif // __cplusplus -/** - * A fixed-size 2D grid of booleans. - * - * The values are stored in packed bytes (8 values per byte) in the same order as used by the display for storing pixels. - * This means that no conversion is necessary for sending the data to the display. - * The downside is that the width has to be a multiple of 8. - * - * # Examples - * - * ```rust - * use servicepoint::Bitmap; - * let mut bitmap = Bitmap::new(8, 2); - * - * ``` - */ -typedef struct Bitmap Bitmap; - -/** - * The raw packet. - * - * Contents should probably only be used directly to use features not exposed by the library. - * - * You may want to use [`crate::Command`] or [`crate::TypedCommand`] instead. - */ -typedef struct Packet Packet; - /** * A vector of bits * @@ -174,51 +99,108 @@ typedef struct Packet Packet; typedef struct SPBitVec SPBitVec; /** - * This enum contains all commands provided by the library. - * This is useful in case you want one data type for all kinds of commands without using `dyn`. + * A grid of pixels. * - * Please look at the contained structs for documentation per command. + * # Examples + * + * ```C + * Cp437Grid grid = sp_bitmap_new(8, 3); + * sp_bitmap_fill(grid, true); + * sp_bitmap_set(grid, 0, 0, false); + * sp_bitmap_free(grid); + * ``` */ -typedef struct Command Command; +typedef struct SPBitmap SPBitmap; /** - * A connection using the UDP protocol. + * A grid containing brightness values. * - * Use this when sending commands directly to the display. + * # Examples + * ```C + * SPConnection connection = sp_connection_open("127.0.0.1:2342"); + * if (connection == NULL) + * return 1; * - * Requires the feature "`protocol_udp`" which is enabled by default. + * SPBrightnessGrid grid = sp_brightness_grid_new(2, 2); + * sp_brightness_grid_set(grid, 0, 0, 0); + * sp_brightness_grid_set(grid, 1, 1, 10); + * + * SPCommand command = sp_command_char_brightness(grid); + * sp_connection_free(connection); + * ``` */ -typedef struct UdpConnection UdpConnection; +typedef struct SPBrightnessGrid SPBrightnessGrid; /** - * A 2D grid of values. + * A C-wrapper for grid containing UTF-8 characters. * - * The memory layout is the one the display expects in [`crate::Command`]s. + * As the rust [char] type is not FFI-safe, characters are passed in their UTF-32 form as 32bit unsigned integers. * - * This structure can be used with any type that implements the [Value] trait. - * You can also use the concrete type aliases provided in this crate, e.g. [`crate::CharGrid`] and [`crate::ByteGrid`]. + * The encoding is enforced in most cases by the rust standard library + * and will panic when provided with illegal characters. + * + * # Examples + * + * ```C + * CharGrid grid = sp_char_grid_new(4, 3); + * sp_char_grid_fill(grid, '?'); + * sp_char_grid_set(grid, 0, 0, '!'); + * sp_char_grid_free(grid); + * ``` */ -typedef struct ValueGrid_Brightness ValueGrid_Brightness; +typedef struct SPCharGrid SPCharGrid; /** - * A 2D grid of values. + * A low-level display command. * - * The memory layout is the one the display expects in [`crate::Command`]s. + * This struct and associated functions implement the UDP protocol for the display. * - * This structure can be used with any type that implements the [Value] trait. - * You can also use the concrete type aliases provided in this crate, e.g. [`crate::CharGrid`] and [`crate::ByteGrid`]. + * To send a [SPCommand], use a [SPConnection]. + * + * # Examples + * + * ```C + * sp_connection_send_command(connection, sp_command_clear()); + * sp_connection_send_command(connection, sp_command_brightness(5)); + * ``` + * + * [SPConnection]: [crate::SPConnection] */ -typedef struct ValueGrid_char ValueGrid_char; +typedef struct SPCommand SPCommand; /** - * A 2D grid of values. + * A connection to the display. * - * The memory layout is the one the display expects in [`crate::Command`]s. + * # Examples * - * This structure can be used with any type that implements the [Value] trait. - * You can also use the concrete type aliases provided in this crate, e.g. [`crate::CharGrid`] and [`crate::ByteGrid`]. + * ```C + * CConnection connection = sp_connection_open("172.23.42.29:2342"); + * if (connection != NULL) + * sp_connection_send_command(connection, sp_command_clear()); + * ``` */ -typedef struct ValueGrid_u8 ValueGrid_u8; +typedef struct SPConnection SPConnection; + +/** + * A C-wrapper for grid containing codepage 437 characters. + * + * The encoding is currently not enforced. + * + * # Examples + * + * ```C + * Cp437Grid grid = sp_cp437_grid_new(4, 3); + * sp_cp437_grid_fill(grid, '?'); + * sp_cp437_grid_set(grid, 0, 0, '!'); + * sp_cp437_grid_free(grid); + * ``` + */ +typedef struct SPCp437Grid SPCp437Grid; + +/** + * The raw packet + */ +typedef struct SPPacket SPPacket; /** * Represents a span of memory (`&mut [u8]` ) as a struct usable by C code. @@ -239,96 +221,13 @@ typedef struct { /** * The start address of the memory */ - uint8_t */*notnull*/ start; + uint8_t *start; /** * The amount of memory in bytes */ size_t length; } SPByteSlice; -/** - * A grid containing brightness values. - * - * # Examples - * - * ```rust - * # use servicepoint::*; - * let mut grid = BrightnessGrid::new(2,2); - * grid.set(0, 0, Brightness::MIN); - * grid.set(1, 1, Brightness::MIN); - * - * # let connection = FakeConnection; - * connection.send(BrightnessGridCommand { - * origin: Origin::new(3, 7), - * grid - * }).unwrap() - * ``` - */ -typedef ValueGrid_Brightness BrightnessGrid; - -/** - * A grid containing UTF-8 characters. - * - * To send a `CharGrid` to the display, use a [`crate::CharGridCommand`]. - * - * Also see [`ValueGrid`] for the non-specialized operations and examples. - * - * # Examples - * - * ```rust - * # use servicepoint::*; - * let grid = CharGrid::from("You can\nload multiline\nstrings directly"); - * assert_eq!(grid.get_row_str(1), Some("load multiline\0\0".to_string())); - * - * # let connection = FakeConnection; - * let command = CharGridCommand { origin: Origin::ZERO, grid }; - * connection.send(command).unwrap() - * ``` - */ -typedef ValueGrid_char CharGrid; - -/** - * A grid containing codepage 437 characters. - * - * The encoding is currently not enforced. - */ -typedef ValueGrid_u8 Cp437Grid; - -/** - * A raw header. - * - * The header specifies the kind of command, the size of the payload and where to display the - * payload, where applicable. - * - * Because the meaning of most fields depend on the command, there are no speaking names for them. - * - * The contained values are in platform endian-ness and may need to be converted before sending. - */ -typedef struct { - /** - * The first two bytes specify which command this packet represents. - */ - uint16_t command_code; - /** - * First command-specific value - */ - uint16_t a; - /** - * Second command-specific value - */ - uint16_t b; - /** - * Third command-specific value - */ - uint16_t c; - /** - * Fourth command-specific value - */ - uint16_t d; -} Header; - - - #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -351,7 +250,7 @@ extern "C" { * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_bitmap_free`. */ -Bitmap */*notnull*/ sp_bitmap_clone(Bitmap */*notnull*/ bitmap); +SPBitmap *sp_bitmap_clone(const SPBitmap *bitmap); /** * Sets the state of all pixels in the [SPBitmap]. @@ -372,7 +271,7 @@ Bitmap */*notnull*/ sp_bitmap_clone(Bitmap */*notnull*/ bitmap); * - `bitmap` points to a valid [SPBitmap] * - `bitmap` is not written to or read from concurrently */ -void sp_bitmap_fill(Bitmap */*notnull*/ bitmap, bool value); +void sp_bitmap_fill(SPBitmap *bitmap, bool value); /** * Deallocates a [SPBitmap]. @@ -386,10 +285,12 @@ void sp_bitmap_fill(Bitmap */*notnull*/ bitmap, bool value); * The caller has to make sure that: * * - `bitmap` points to a valid [SPBitmap] + * - `bitmap` is not used concurrently or after bitmap call + * - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] * * [SPCommand]: [crate::SPCommand] */ -void sp_bitmap_free(Bitmap */*notnull*/ bitmap); +void sp_bitmap_free(SPBitmap *bitmap); /** * Gets the current value at the specified position in the [SPBitmap]. @@ -411,7 +312,7 @@ void sp_bitmap_free(Bitmap */*notnull*/ bitmap); * - `bitmap` points to a valid [SPBitmap] * - `bitmap` is not written to concurrently */ -bool sp_bitmap_get(Bitmap */*notnull*/ bitmap, size_t x, size_t y); +bool sp_bitmap_get(const SPBitmap *bitmap, size_t x, size_t y); /** * Gets the height in pixels of the [SPBitmap] instance. @@ -430,7 +331,7 @@ bool sp_bitmap_get(Bitmap */*notnull*/ bitmap, size_t x, size_t y); * * - `bitmap` points to a valid [SPBitmap] */ -size_t sp_bitmap_height(Bitmap */*notnull*/ bitmap); +size_t sp_bitmap_height(const SPBitmap *bitmap); /** * Loads a [SPBitmap] with the specified dimensions from the provided data. @@ -461,9 +362,10 @@ size_t sp_bitmap_height(Bitmap */*notnull*/ bitmap); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_bitmap_free`. */ -Bitmap *sp_bitmap_load(size_t width, - size_t height, - SPByteSlice data); +SPBitmap *sp_bitmap_load(size_t width, + size_t height, + const uint8_t *data, + size_t data_length); /** * Creates a new [SPBitmap] with the specified dimensions. @@ -488,8 +390,8 @@ Bitmap *sp_bitmap_load(size_t width, * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_bitmap_free`. */ -Bitmap *sp_bitmap_new(size_t width, - size_t height); +SPBitmap *sp_bitmap_new(size_t width, + size_t height); /** * Creates a new [SPBitmap] with a size matching the screen. @@ -503,7 +405,7 @@ Bitmap *sp_bitmap_new(size_t width, * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling [sp_bitmap_free]. */ -Bitmap */*notnull*/ sp_bitmap_new_screen_sized(void); +SPBitmap *sp_bitmap_new_screen_sized(void); /** * Sets the value of the specified position in the [SPBitmap]. @@ -528,7 +430,7 @@ Bitmap */*notnull*/ sp_bitmap_new_screen_sized(void); * - `bitmap` points to a valid [SPBitmap] * - `bitmap` is not written to or read from concurrently */ -void sp_bitmap_set(Bitmap */*notnull*/ bitmap, size_t x, size_t y, bool value); +void sp_bitmap_set(SPBitmap *bitmap, size_t x, size_t y, bool value); /** * Gets an unsafe reference to the data of the [SPBitmap] instance. @@ -545,7 +447,7 @@ void sp_bitmap_set(Bitmap */*notnull*/ bitmap, size_t x, size_t y, bool value); * - the returned memory range is never accessed after the passed [SPBitmap] has been freed * - the returned memory range is never accessed concurrently, either via the [SPBitmap] or directly */ -SPByteSlice sp_bitmap_unsafe_data_ref(Bitmap */*notnull*/ bitmap); +SPByteSlice sp_bitmap_unsafe_data_ref(SPBitmap *bitmap); /** * Gets the width in pixels of the [SPBitmap] instance. @@ -564,7 +466,7 @@ SPByteSlice sp_bitmap_unsafe_data_ref(Bitmap */*notnull*/ bitmap); * * - `bitmap` points to a valid [SPBitmap] */ -size_t sp_bitmap_width(Bitmap */*notnull*/ bitmap); +size_t sp_bitmap_width(const SPBitmap *bitmap); /** * Clones a [SPBitVec]. @@ -584,7 +486,7 @@ size_t sp_bitmap_width(Bitmap */*notnull*/ bitmap); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_bitvec_free`. */ -SPBitVec */*notnull*/ sp_bitvec_clone(SPBitVec */*notnull*/ bit_vec); +SPBitVec *sp_bitvec_clone(const SPBitVec *bit_vec); /** * Sets the value of all bits in the [SPBitVec]. @@ -605,7 +507,7 @@ SPBitVec */*notnull*/ sp_bitvec_clone(SPBitVec */*notnull*/ bit_vec); * - `bit_vec` points to a valid [SPBitVec] * - `bit_vec` is not written to or read from concurrently */ -void sp_bitvec_fill(SPBitVec */*notnull*/ bit_vec, bool value); +void sp_bitvec_fill(SPBitVec *bit_vec, bool value); /** * Deallocates a [SPBitVec]. @@ -624,7 +526,7 @@ void sp_bitvec_fill(SPBitVec */*notnull*/ bit_vec, bool value); * * [SPCommand]: [crate::SPCommand] */ -void sp_bitvec_free(SPBitVec */*notnull*/ bit_vec); +void sp_bitvec_free(SPBitVec *bit_vec); /** * Gets the value of a bit from the [SPBitVec]. @@ -648,7 +550,7 @@ void sp_bitvec_free(SPBitVec */*notnull*/ bit_vec); * - `bit_vec` points to a valid [SPBitVec] * - `bit_vec` is not written to concurrently */ -bool sp_bitvec_get(SPBitVec */*notnull*/ bit_vec, size_t index); +bool sp_bitvec_get(const SPBitVec *bit_vec, size_t index); /** * Returns true if length is 0. @@ -667,7 +569,7 @@ bool sp_bitvec_get(SPBitVec */*notnull*/ bit_vec, size_t index); * * - `bit_vec` points to a valid [SPBitVec] */ -bool sp_bitvec_is_empty(SPBitVec */*notnull*/ bit_vec); +bool sp_bitvec_is_empty(const SPBitVec *bit_vec); /** * Gets the length of the [SPBitVec] in bits. @@ -686,7 +588,7 @@ bool sp_bitvec_is_empty(SPBitVec */*notnull*/ bit_vec); * * - `bit_vec` points to a valid [SPBitVec] */ -size_t sp_bitvec_len(SPBitVec */*notnull*/ bit_vec); +size_t sp_bitvec_len(const SPBitVec *bit_vec); /** * Interpret the data as a series of bits and load then into a new [SPBitVec] instance. @@ -706,7 +608,8 @@ size_t sp_bitvec_len(SPBitVec */*notnull*/ bit_vec); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_bitvec_free`. */ -SPBitVec */*notnull*/ sp_bitvec_load(SPByteSlice data); +SPBitVec *sp_bitvec_load(const uint8_t *data, + size_t data_length); /** * Creates a new [SPBitVec] instance. @@ -728,7 +631,7 @@ SPBitVec */*notnull*/ sp_bitvec_load(SPByteSlice data); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_bitvec_free`. */ -SPBitVec */*notnull*/ sp_bitvec_new(size_t size); +SPBitVec *sp_bitvec_new(size_t size); /** * Sets the value of a bit in the [SPBitVec]. @@ -751,7 +654,7 @@ SPBitVec */*notnull*/ sp_bitvec_new(size_t size); * - `bit_vec` points to a valid [SPBitVec] * - `bit_vec` is not written to or read from concurrently */ -void sp_bitvec_set(SPBitVec */*notnull*/ bit_vec, size_t index, bool value); +void sp_bitvec_set(SPBitVec *bit_vec, size_t index, bool value); /** * Gets an unsafe reference to the data of the [SPBitVec] instance. @@ -772,7 +675,7 @@ void sp_bitvec_set(SPBitVec */*notnull*/ bit_vec, size_t index, bool value); * - the returned memory range is never accessed after the passed [SPBitVec] has been freed * - the returned memory range is never accessed concurrently, either via the [SPBitVec] or directly */ -SPByteSlice sp_bitvec_unsafe_data_ref(SPBitVec */*notnull*/ bit_vec); +SPByteSlice sp_bitvec_unsafe_data_ref(SPBitVec *bit_vec); /** * Clones a [SPBrightnessGrid]. @@ -796,7 +699,7 @@ SPByteSlice sp_bitvec_unsafe_data_ref(SPBitVec */*notnull*/ bit_vec); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_brightness_grid_free`. */ -BrightnessGrid */*notnull*/ sp_brightness_grid_clone(BrightnessGrid */*notnull*/ brightness_grid); +SPBrightnessGrid *sp_brightness_grid_clone(const SPBrightnessGrid *brightness_grid); /** * Sets the value of all cells in the [SPBrightnessGrid]. @@ -818,8 +721,7 @@ BrightnessGrid */*notnull*/ sp_brightness_grid_clone(BrightnessGrid */*notnull*/ * - `brightness_grid` points to a valid [SPBrightnessGrid] * - `brightness_grid` is not written to or read from concurrently */ -void sp_brightness_grid_fill(BrightnessGrid */*notnull*/ brightness_grid, - uint8_t value); +void sp_brightness_grid_fill(SPBrightnessGrid *brightness_grid, uint8_t value); /** * Deallocates a [SPBrightnessGrid]. @@ -842,7 +744,7 @@ void sp_brightness_grid_fill(BrightnessGrid */*notnull*/ brightness_grid, * * [SPCommand]: [crate::SPCommand] */ -void sp_brightness_grid_free(BrightnessGrid */*notnull*/ brightness_grid); +void sp_brightness_grid_free(SPBrightnessGrid *brightness_grid); /** * Gets the current value at the specified position. @@ -866,7 +768,7 @@ void sp_brightness_grid_free(BrightnessGrid */*notnull*/ brightness_grid); * - `brightness_grid` points to a valid [SPBrightnessGrid] * - `brightness_grid` is not written to concurrently */ -uint8_t sp_brightness_grid_get(BrightnessGrid */*notnull*/ brightness_grid, +uint8_t sp_brightness_grid_get(const SPBrightnessGrid *brightness_grid, size_t x, size_t y); @@ -889,7 +791,7 @@ uint8_t sp_brightness_grid_get(BrightnessGrid */*notnull*/ brightness_grid, * * - `brightness_grid` points to a valid [SPBrightnessGrid] */ -size_t sp_brightness_grid_height(BrightnessGrid */*notnull*/ brightness_grid); +size_t sp_brightness_grid_height(const SPBrightnessGrid *brightness_grid); /** * Loads a [SPBrightnessGrid] with the specified dimensions from the provided data. @@ -910,9 +812,10 @@ size_t sp_brightness_grid_height(BrightnessGrid */*notnull*/ brightness_grid); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_brightness_grid_free`. */ -BrightnessGrid *sp_brightness_grid_load(size_t width, - size_t height, - SPByteSlice data); +SPBrightnessGrid *sp_brightness_grid_load(size_t width, + size_t height, + const uint8_t *data, + size_t data_length); /** * Creates a new [SPBrightnessGrid] with the specified dimensions. @@ -926,8 +829,8 @@ BrightnessGrid *sp_brightness_grid_load(size_t width, * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_brightness_grid_free`. */ -BrightnessGrid */*notnull*/ sp_brightness_grid_new(size_t width, - size_t height); +SPBrightnessGrid *sp_brightness_grid_new(size_t width, + size_t height); /** * Sets the value of the specified position in the [SPBrightnessGrid]. @@ -953,7 +856,7 @@ BrightnessGrid */*notnull*/ sp_brightness_grid_new(size_t width, * - `brightness_grid` points to a valid [SPBrightnessGrid] * - `brightness_grid` is not written to or read from concurrently */ -void sp_brightness_grid_set(BrightnessGrid */*notnull*/ brightness_grid, +void sp_brightness_grid_set(SPBrightnessGrid *brightness_grid, size_t x, size_t y, uint8_t value); @@ -979,7 +882,7 @@ void sp_brightness_grid_set(BrightnessGrid */*notnull*/ brightness_grid, * - the returned memory range is never accessed after the passed [SPBrightnessGrid] has been freed * - the returned memory range is never accessed concurrently, either via the [SPBrightnessGrid] or directly */ -SPByteSlice sp_brightness_grid_unsafe_data_ref(BrightnessGrid */*notnull*/ brightness_grid); +SPByteSlice sp_brightness_grid_unsafe_data_ref(SPBrightnessGrid *brightness_grid); /** * Gets the width of the [SPBrightnessGrid] instance. @@ -1000,7 +903,7 @@ SPByteSlice sp_brightness_grid_unsafe_data_ref(BrightnessGrid */*notnull*/ brigh * * - `brightness_grid` points to a valid [SPBrightnessGrid] */ -size_t sp_brightness_grid_width(BrightnessGrid */*notnull*/ brightness_grid); +size_t sp_brightness_grid_width(const SPBrightnessGrid *brightness_grid); /** * Clones a [SPCharGrid]. @@ -1020,7 +923,7 @@ size_t sp_brightness_grid_width(BrightnessGrid */*notnull*/ brightness_grid); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_char_grid_free`. */ -CharGrid */*notnull*/ sp_char_grid_clone(CharGrid */*notnull*/ char_grid); +SPCharGrid *sp_char_grid_clone(const SPCharGrid *char_grid); /** * Sets the value of all cells in the [SPCharGrid]. @@ -1041,7 +944,7 @@ CharGrid */*notnull*/ sp_char_grid_clone(CharGrid */*notnull*/ char_grid); * - `char_grid` points to a valid [SPCharGrid] * - `char_grid` is not written to or read from concurrently */ -void sp_char_grid_fill(CharGrid */*notnull*/ char_grid, uint32_t value); +void sp_char_grid_fill(SPCharGrid *char_grid, uint32_t value); /** * Deallocates a [SPCharGrid]. @@ -1060,7 +963,7 @@ void sp_char_grid_fill(CharGrid */*notnull*/ char_grid, uint32_t value); * * [SPCommand]: [crate::SPCommand] */ -void sp_char_grid_free(CharGrid */*notnull*/ char_grid); +void sp_char_grid_free(SPCharGrid *char_grid); /** * Gets the current value at the specified position. @@ -1082,7 +985,7 @@ void sp_char_grid_free(CharGrid */*notnull*/ char_grid); * - `char_grid` points to a valid [SPCharGrid] * - `char_grid` is not written to concurrently */ -uint32_t sp_char_grid_get(CharGrid */*notnull*/ char_grid, size_t x, size_t y); +uint32_t sp_char_grid_get(const SPCharGrid *char_grid, size_t x, size_t y); /** * Gets the height of the [SPCharGrid] instance. @@ -1101,7 +1004,7 @@ uint32_t sp_char_grid_get(CharGrid */*notnull*/ char_grid, size_t x, size_t y); * * - `char_grid` points to a valid [SPCharGrid] */ -size_t sp_char_grid_height(CharGrid */*notnull*/ char_grid); +size_t sp_char_grid_height(const SPCharGrid *char_grid); /** * Loads a [SPCharGrid] with the specified dimensions from the provided data. @@ -1123,9 +1026,10 @@ size_t sp_char_grid_height(CharGrid */*notnull*/ char_grid); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_char_grid_free`. */ -CharGrid */*notnull*/ sp_char_grid_load(size_t width, - size_t height, - SPByteSlice data); +SPCharGrid *sp_char_grid_load(size_t width, + size_t height, + const uint8_t *data, + size_t data_length); /** * Creates a new [SPCharGrid] with the specified dimensions. @@ -1139,8 +1043,8 @@ CharGrid */*notnull*/ sp_char_grid_load(size_t width, * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_char_grid_free`. */ -CharGrid */*notnull*/ sp_char_grid_new(size_t width, - size_t height); +SPCharGrid *sp_char_grid_new(size_t width, + size_t height); /** * Sets the value of the specified position in the [SPCharGrid]. @@ -1167,7 +1071,7 @@ CharGrid */*notnull*/ sp_char_grid_new(size_t width, * * [SPBitVec]: [crate::SPBitVec] */ -void sp_char_grid_set(CharGrid */*notnull*/ char_grid, +void sp_char_grid_set(SPCharGrid *char_grid, size_t x, size_t y, uint32_t value); @@ -1189,7 +1093,7 @@ void sp_char_grid_set(CharGrid */*notnull*/ char_grid, * * - `char_grid` points to a valid [SPCharGrid] */ -size_t sp_char_grid_width(CharGrid */*notnull*/ char_grid); +size_t sp_char_grid_width(const SPCharGrid *char_grid); /** * Set pixel data starting at the pixel offset on screen. @@ -1218,9 +1122,9 @@ size_t sp_char_grid_width(CharGrid */*notnull*/ char_grid); * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command *sp_command_bitmap_linear(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); +SPCommand *sp_command_bitmap_linear(size_t offset, + SPBitVec *bit_vec, + SPCompressionCode compression); /** * Set pixel data according to an and-mask starting at the offset. @@ -1249,9 +1153,9 @@ Command *sp_command_bitmap_linear(size_t offset, * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command *sp_command_bitmap_linear_and(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); +SPCommand *sp_command_bitmap_linear_and(size_t offset, + SPBitVec *bit_vec, + SPCompressionCode compression); /** * Set pixel data according to an or-mask starting at the offset. @@ -1280,9 +1184,9 @@ Command *sp_command_bitmap_linear_and(size_t offset, * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command *sp_command_bitmap_linear_or(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); +SPCommand *sp_command_bitmap_linear_or(size_t offset, + SPBitVec *bit_vec, + SPCompressionCode compression); /** * Sets a window of pixels to the specified values. @@ -1306,10 +1210,10 @@ Command *sp_command_bitmap_linear_or(size_t offset, * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command *sp_command_bitmap_linear_win(size_t x, - size_t y, - Bitmap */*notnull*/ bitmap, - CompressionCode compression); +SPCommand *sp_command_bitmap_linear_win(size_t x, + size_t y, + SPBitmap *bitmap, + SPCompressionCode compression); /** * Set pixel data according to a xor-mask starting at the offset. @@ -1338,9 +1242,9 @@ Command *sp_command_bitmap_linear_win(size_t x, * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command *sp_command_bitmap_linear_xor(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); +SPCommand *sp_command_bitmap_linear_xor(size_t offset, + SPBitVec *bit_vec, + SPCompressionCode compression); /** * Set the brightness of all tiles to the same value. @@ -1358,7 +1262,7 @@ Command *sp_command_bitmap_linear_xor(size_t offset, * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command */*notnull*/ sp_command_brightness(uint8_t brightness); +SPCommand *sp_command_brightness(uint8_t brightness); /** * Set the brightness of individual tiles in a rectangular area of the display. @@ -1380,9 +1284,9 @@ Command */*notnull*/ sp_command_brightness(uint8_t brightness); * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command */*notnull*/ sp_command_char_brightness(size_t x, - size_t y, - BrightnessGrid */*notnull*/ grid); +SPCommand *sp_command_char_brightness(size_t x, + size_t y, + SPBrightnessGrid *grid); /** * Set all pixels to the off state. @@ -1404,7 +1308,7 @@ Command */*notnull*/ sp_command_char_brightness(size_t x, * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command */*notnull*/ sp_command_clear(void); +SPCommand *sp_command_clear(void); /** * Clones a [SPCommand] instance. @@ -1424,7 +1328,7 @@ Command */*notnull*/ sp_command_clear(void); * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command */*notnull*/ sp_command_clone(Command */*notnull*/ command); +SPCommand *sp_command_clone(const SPCommand *command); /** * Show codepage 437 encoded text on the screen. @@ -1446,9 +1350,9 @@ Command */*notnull*/ sp_command_clone(Command */*notnull*/ command); * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command */*notnull*/ sp_command_cp437_data(size_t x, - size_t y, - Cp437Grid */*notnull*/ grid); +SPCommand *sp_command_cp437_data(size_t x, + size_t y, + SPCp437Grid *grid); /** * A yet-to-be-tested command. @@ -1462,7 +1366,7 @@ Command */*notnull*/ sp_command_cp437_data(size_t x, * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command */*notnull*/ sp_command_fade_out(void); +SPCommand *sp_command_fade_out(void); /** * Deallocates a [SPCommand]. @@ -1486,7 +1390,7 @@ Command */*notnull*/ sp_command_fade_out(void); * - `command` is not used concurrently or after this call * - `command` was not passed to another consuming function, e.g. to create a [SPPacket] */ -void sp_command_free(Command */*notnull*/ command); +void sp_command_free(SPCommand *command); /** * Kills the udp daemon on the display, which usually results in a restart. @@ -1502,23 +1406,9 @@ void sp_command_free(Command */*notnull*/ command); * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command */*notnull*/ sp_command_hard_reset(void); +SPCommand *sp_command_hard_reset(void); /** - * A low-level display command. - * - * This struct and associated functions implement the UDP protocol for the display. - * - * To send a [SPCommand], use a [SPConnection]. - * - * # Examples - * - * ```C - * sp_connection_send_command(connection, sp_command_clear()); - * sp_connection_send_command(connection, sp_command_brightness(5)); - * ``` - * - * [SPConnection]: [crate::SPConnection] * Tries to turn a [SPPacket] into a [SPCommand]. * * The packet is deallocated in the process. @@ -1539,7 +1429,7 @@ Command */*notnull*/ sp_command_hard_reset(void); * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command *sp_command_try_from_packet(Packet */*notnull*/ packet); +SPCommand *sp_command_try_from_packet(SPPacket *packet); /** * Show UTF-8 encoded text on the screen. @@ -1561,9 +1451,9 @@ Command *sp_command_try_from_packet(Packet */*notnull*/ packet); * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -Command */*notnull*/ sp_command_utf8_data(size_t x, - size_t y, - CharGrid */*notnull*/ grid); +SPCommand *sp_command_utf8_data(size_t x, + size_t y, + SPCharGrid *grid); /** * Closes and deallocates a [SPConnection]. @@ -1579,7 +1469,7 @@ Command */*notnull*/ sp_command_utf8_data(size_t x, * - `connection` points to a valid [SPConnection] * - `connection` is not used concurrently or after this call */ -void sp_connection_free(UdpConnection */*notnull*/ connection); +void sp_connection_free(SPConnection *connection); /** * Creates a new instance of [SPConnection]. @@ -1597,7 +1487,7 @@ void sp_connection_free(UdpConnection */*notnull*/ connection); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_connection_free`. */ -UdpConnection *sp_connection_open(char */*notnull*/ host); +SPConnection *sp_connection_open(const char *host); /** * Sends a [SPCommand] to the display using the [SPConnection]. @@ -1619,8 +1509,8 @@ UdpConnection *sp_connection_open(char */*notnull*/ host); * - `command` points to a valid instance of [SPPacket] * - `command` is not used concurrently or after this call */ -bool sp_connection_send_command(UdpConnection */*notnull*/ connection, - Command */*notnull*/ command); +bool sp_connection_send_command(const SPConnection *connection, + SPCommand *command); /** * Sends a [SPPacket] to the display using the [SPConnection]. @@ -1642,8 +1532,8 @@ bool sp_connection_send_command(UdpConnection */*notnull*/ connection, * - `packet` points to a valid instance of [SPPacket] * - `packet` is not used concurrently or after this call */ -bool sp_connection_send_packet(UdpConnection */*notnull*/ connection, - Packet */*notnull*/ packet); +bool sp_connection_send_packet(const SPConnection *connection, + SPPacket *packet); /** * Clones a [SPCp437Grid]. @@ -1663,7 +1553,7 @@ bool sp_connection_send_packet(UdpConnection */*notnull*/ connection, * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_cp437_grid_free`. */ -Cp437Grid */*notnull*/ sp_cp437_grid_clone(Cp437Grid */*notnull*/ cp437_grid); +SPCp437Grid *sp_cp437_grid_clone(const SPCp437Grid *cp437_grid); /** * Sets the value of all cells in the [SPCp437Grid]. @@ -1684,7 +1574,7 @@ Cp437Grid */*notnull*/ sp_cp437_grid_clone(Cp437Grid */*notnull*/ cp437_grid); * - `cp437_grid` points to a valid [SPCp437Grid] * - `cp437_grid` is not written to or read from concurrently */ -void sp_cp437_grid_fill(Cp437Grid */*notnull*/ cp437_grid, uint8_t value); +void sp_cp437_grid_fill(SPCp437Grid *cp437_grid, uint8_t value); /** * Deallocates a [SPCp437Grid]. @@ -1703,7 +1593,7 @@ void sp_cp437_grid_fill(Cp437Grid */*notnull*/ cp437_grid, uint8_t value); * * [SPCommand]: [crate::SPCommand] */ -void sp_cp437_grid_free(Cp437Grid */*notnull*/ cp437_grid); +void sp_cp437_grid_free(SPCp437Grid *cp437_grid); /** * Gets the current value at the specified position. @@ -1725,9 +1615,7 @@ void sp_cp437_grid_free(Cp437Grid */*notnull*/ cp437_grid); * - `cp437_grid` points to a valid [SPCp437Grid] * - `cp437_grid` is not written to concurrently */ -uint8_t sp_cp437_grid_get(Cp437Grid */*notnull*/ cp437_grid, - size_t x, - size_t y); +uint8_t sp_cp437_grid_get(const SPCp437Grid *cp437_grid, size_t x, size_t y); /** * Gets the height of the [SPCp437Grid] instance. @@ -1746,7 +1634,7 @@ uint8_t sp_cp437_grid_get(Cp437Grid */*notnull*/ cp437_grid, * * - `cp437_grid` points to a valid [SPCp437Grid] */ -size_t sp_cp437_grid_height(Cp437Grid */*notnull*/ cp437_grid); +size_t sp_cp437_grid_height(const SPCp437Grid *cp437_grid); /** * Loads a [SPCp437Grid] with the specified dimensions from the provided data. @@ -1767,9 +1655,10 @@ size_t sp_cp437_grid_height(Cp437Grid */*notnull*/ cp437_grid); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_cp437_grid_free`. */ -Cp437Grid *sp_cp437_grid_load(size_t width, - size_t height, - SPByteSlice data); +SPCp437Grid *sp_cp437_grid_load(size_t width, + size_t height, + const uint8_t *data, + size_t data_length); /** * Creates a new [SPCp437Grid] with the specified dimensions. @@ -1783,8 +1672,8 @@ Cp437Grid *sp_cp437_grid_load(size_t width, * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_cp437_grid_free`. */ -Cp437Grid */*notnull*/ sp_cp437_grid_new(size_t width, - size_t height); +SPCp437Grid *sp_cp437_grid_new(size_t width, + size_t height); /** * Sets the value of the specified position in the [SPCp437Grid]. @@ -1811,7 +1700,7 @@ Cp437Grid */*notnull*/ sp_cp437_grid_new(size_t width, * * [SPBitVec]: [crate::SPBitVec] */ -void sp_cp437_grid_set(Cp437Grid */*notnull*/ cp437_grid, +void sp_cp437_grid_set(SPCp437Grid *cp437_grid, size_t x, size_t y, uint8_t value); @@ -1833,7 +1722,7 @@ void sp_cp437_grid_set(Cp437Grid */*notnull*/ cp437_grid, * - the returned memory range is never accessed after the passed [SPCp437Grid] has been freed * - the returned memory range is never accessed concurrently, either via the [SPCp437Grid] or directly */ -SPByteSlice sp_cp437_grid_unsafe_data_ref(Cp437Grid */*notnull*/ cp437_grid); +SPByteSlice sp_cp437_grid_unsafe_data_ref(SPCp437Grid *cp437_grid); /** * Gets the width of the [SPCp437Grid] instance. @@ -1852,7 +1741,7 @@ SPByteSlice sp_cp437_grid_unsafe_data_ref(Cp437Grid */*notnull*/ cp437_grid); * * - `cp437_grid` points to a valid [SPCp437Grid] */ -size_t sp_cp437_grid_width(Cp437Grid */*notnull*/ cp437_grid); +size_t sp_cp437_grid_width(const SPCp437Grid *cp437_grid); /** * Clones a [SPPacket]. @@ -1872,7 +1761,7 @@ size_t sp_cp437_grid_width(Cp437Grid */*notnull*/ cp437_grid); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_packet_free`. */ -Packet */*notnull*/ sp_packet_clone(Packet */*notnull*/ packet); +SPPacket *sp_packet_clone(const SPPacket *packet); /** * Deallocates a [SPPacket]. @@ -1888,7 +1777,7 @@ Packet */*notnull*/ sp_packet_clone(Packet */*notnull*/ packet); * - `packet` points to a valid [SPPacket] * - `packet` is not used concurrently or after this call */ -void sp_packet_free(Packet */*notnull*/ packet); +void sp_packet_free(SPPacket *packet); /** * Turns a [SPCommand] into a [SPPacket]. @@ -1909,7 +1798,7 @@ void sp_packet_free(Packet */*notnull*/ packet); * - the returned [SPPacket] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_packet_free`. */ -Packet *sp_packet_from_command(Command */*notnull*/ command); +SPPacket *sp_packet_from_command(SPCommand *command); /** * Creates a raw [SPPacket] from parts. @@ -1937,14 +1826,13 @@ Packet *sp_packet_from_command(Command */*notnull*/ command); * - the returned [SPPacket] instance is freed in some way, either by using a consuming function or * by explicitly calling [sp_packet_free]. */ -Packet */*notnull*/ sp_packet_from_parts(Header header, - const SPByteSlice *payload); - -Header */*notnull*/ sp_packet_get_header(Packet */*notnull*/ packet); - -SPByteSlice sp_packet_get_payload(Packet */*notnull*/ packet); - -void sp_packet_set_payload(Packet */*notnull*/ packet, SPByteSlice data); +SPPacket *sp_packet_from_parts(uint16_t command_code, + uint16_t a, + uint16_t b, + uint16_t c, + uint16_t d, + const uint8_t *payload, + size_t payload_len); /** * Tries to load a [SPPacket] from the passed array with the specified length. @@ -1964,9 +1852,8 @@ void sp_packet_set_payload(Packet */*notnull*/ packet, SPByteSlice data); * - the returned [SPPacket] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_packet_free`. */ -Packet *sp_packet_try_load(SPByteSlice data); - -void sp_packet_write_to(Packet */*notnull*/ packet, SPByteSlice buffer); +SPPacket *sp_packet_try_load(const uint8_t *data, + size_t length); #ifdef __cplusplus } // extern "C" diff --git a/examples/lang_c/src/main.c b/examples/lang_c/src/main.c index 80a1756..6a4b30e 100644 --- a/examples/lang_c/src/main.c +++ b/examples/lang_c/src/main.c @@ -2,26 +2,21 @@ #include "servicepoint.h" int main(void) { - UdpConnection *connection = sp_connection_open("localhost:2342"); + SPConnection *connection = sp_connection_open("localhost:2342"); if (connection == NULL) return 1; - Bitmap *pixels = sp_bitmap_new(PIXEL_WIDTH, PIXEL_HEIGHT); + SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT); if (pixels == NULL) return 1; sp_bitmap_fill(pixels, true); - Command *command = sp_command_bitmap_linear_win(0, 0, pixels, COMPRESSION_CODE_UNCOMPRESSED); + SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, SP_COMPRESSION_CODE_UNCOMPRESSED); if (command == NULL) return 1; - Packet *packet = sp_packet_from_command(command); - - Header *header = sp_packet_get_header(packet); - printf("[%d, %d, %d, %d, %d]\n", header->command_code, header->a, header->b, header->c, header->d); - - sp_connection_send_packet(connection, packet); + sp_connection_send_command(connection, command); sp_connection_free(connection); return 0; diff --git a/src/bitmap.rs b/src/bitmap.rs index 2e70efc..eee5d24 100644 --- a/src/bitmap.rs +++ b/src/bitmap.rs @@ -1,23 +1,24 @@ //! C functions for interacting with [SPBitmap]s //! //! prefix `sp_bitmap_` -//! -//! A grid of pixels. -//! -//! # Examples -//! -//! ```C -//! Cp437Grid grid = sp_bitmap_new(8, 3); -//! sp_bitmap_fill(grid, true); -//! sp_bitmap_set(grid, 0, 0, false); -//! sp_bitmap_free(grid); -//! ``` -use servicepoint::{Bitmap, DataRef, Grid}; +use servicepoint::{DataRef, Grid}; use std::ptr::NonNull; use crate::byte_slice::SPByteSlice; +/// A grid of pixels. +/// +/// # Examples +/// +/// ```C +/// Cp437Grid grid = sp_bitmap_new(8, 3); +/// sp_bitmap_fill(grid, true); +/// sp_bitmap_set(grid, 0, 0, false); +/// sp_bitmap_free(grid); +/// ``` +pub struct SPBitmap(pub(crate) servicepoint::Bitmap); + /// Creates a new [SPBitmap] with the specified dimensions. /// /// # Arguments @@ -43,9 +44,9 @@ use crate::byte_slice::SPByteSlice; pub unsafe extern "C" fn sp_bitmap_new( width: usize, height: usize, -) -> *mut Bitmap { - if let Some(bitmap) = Bitmap::new(width, height) { - Box::leak(Box::new(bitmap)) +) -> *mut SPBitmap { + if let Some(bitmap) = servicepoint::Bitmap::new(width, height) { + Box::leak(Box::new(SPBitmap(bitmap))) } else { std::ptr::null_mut() } @@ -62,8 +63,8 @@ pub unsafe extern "C" fn sp_bitmap_new( /// - the returned instance is freed in some way, either by using a consuming function or /// by explicitly calling [sp_bitmap_free]. #[no_mangle] -pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull { - let result = Box::new(Bitmap::max_sized()); +pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull { + let result = Box::new(SPBitmap(servicepoint::Bitmap::max_sized())); NonNull::from(Box::leak(result)) } @@ -98,11 +99,13 @@ pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull { pub unsafe extern "C" fn sp_bitmap_load( width: usize, height: usize, - data: SPByteSlice, -) -> *mut Bitmap { - let data = unsafe { data.as_slice() }; - if let Ok(bitmap) = Bitmap::load(width, height, data) { - Box::leak(Box::new(bitmap)) + data: *const u8, + data_length: usize, +) -> *mut SPBitmap { + assert!(!data.is_null()); + 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() } @@ -126,9 +129,10 @@ pub unsafe extern "C" fn sp_bitmap_load( /// by explicitly calling `sp_bitmap_free`. #[no_mangle] pub unsafe extern "C" fn sp_bitmap_clone( - bitmap: NonNull, -) -> NonNull { - let result = Box::new(unsafe { bitmap.as_ref().clone() }); + bitmap: *const SPBitmap, +) -> NonNull { + assert!(!bitmap.is_null()); + let result = Box::new(SPBitmap(unsafe { (*bitmap).0.clone() })); NonNull::from(Box::leak(result)) } @@ -143,11 +147,14 @@ pub unsafe extern "C" fn sp_bitmap_clone( /// The caller has to make sure that: /// /// - `bitmap` points to a valid [SPBitmap] +/// - `bitmap` is not used concurrently or after bitmap call +/// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] /// /// [SPCommand]: [crate::SPCommand] #[no_mangle] -pub unsafe extern "C" fn sp_bitmap_free(bitmap: NonNull) { - _ = unsafe { Box::from_raw(bitmap.as_ptr()) }; +pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) { + assert!(!bitmap.is_null()); + _ = unsafe { Box::from_raw(bitmap) }; } /// Gets the current value at the specified position in the [SPBitmap]. @@ -170,11 +177,12 @@ pub unsafe extern "C" fn sp_bitmap_free(bitmap: NonNull) { /// - `bitmap` is not written to concurrently #[no_mangle] pub unsafe extern "C" fn sp_bitmap_get( - bitmap: NonNull, + bitmap: *const SPBitmap, x: usize, y: usize, ) -> bool { - unsafe { bitmap.as_ref().get(x, y) } + assert!(!bitmap.is_null()); + unsafe { (*bitmap).0.get(x, y) } } /// Sets the value of the specified position in the [SPBitmap]. @@ -200,12 +208,13 @@ pub unsafe extern "C" fn sp_bitmap_get( /// - `bitmap` is not written to or read from concurrently #[no_mangle] pub unsafe extern "C" fn sp_bitmap_set( - bitmap: NonNull, + bitmap: *mut SPBitmap, x: usize, y: usize, value: bool, ) { - unsafe { (*bitmap.as_ptr()).set(x, y, value) }; + assert!(!bitmap.is_null()); + unsafe { (*bitmap).0.set(x, y, value) }; } /// Sets the state of all pixels in the [SPBitmap]. @@ -226,8 +235,9 @@ pub unsafe extern "C" fn sp_bitmap_set( /// - `bitmap` points to a valid [SPBitmap] /// - `bitmap` is not written to or read from concurrently #[no_mangle] -pub unsafe extern "C" fn sp_bitmap_fill(bitmap: NonNull, value: bool) { - unsafe { (*bitmap.as_ptr()).fill(value) }; +pub unsafe extern "C" fn sp_bitmap_fill(bitmap: *mut SPBitmap, value: bool) { + assert!(!bitmap.is_null()); + unsafe { (*bitmap).0.fill(value) }; } /// Gets the width in pixels of the [SPBitmap] instance. @@ -246,8 +256,9 @@ pub unsafe extern "C" fn sp_bitmap_fill(bitmap: NonNull, value: bool) { /// /// - `bitmap` points to a valid [SPBitmap] #[no_mangle] -pub unsafe extern "C" fn sp_bitmap_width(bitmap: NonNull) -> usize { - unsafe { bitmap.as_ref().width() } +pub unsafe extern "C" fn sp_bitmap_width(bitmap: *const SPBitmap) -> usize { + assert!(!bitmap.is_null()); + unsafe { (*bitmap).0.width() } } /// Gets the height in pixels of the [SPBitmap] instance. @@ -266,8 +277,9 @@ pub unsafe extern "C" fn sp_bitmap_width(bitmap: NonNull) -> usize { /// /// - `bitmap` points to a valid [SPBitmap] #[no_mangle] -pub unsafe extern "C" fn sp_bitmap_height(bitmap: NonNull) -> usize { - unsafe { bitmap.as_ref().height() } +pub unsafe extern "C" fn sp_bitmap_height(bitmap: *const SPBitmap) -> usize { + assert!(!bitmap.is_null()); + unsafe { (*bitmap).0.height() } } /// Gets an unsafe reference to the data of the [SPBitmap] instance. @@ -285,7 +297,12 @@ pub unsafe extern "C" fn sp_bitmap_height(bitmap: NonNull) -> usize { /// - the returned memory range is never accessed concurrently, either via the [SPBitmap] or directly #[no_mangle] pub unsafe extern "C" fn sp_bitmap_unsafe_data_ref( - mut bitmap: NonNull, + bitmap: *mut SPBitmap, ) -> SPByteSlice { - unsafe { SPByteSlice::from_slice(bitmap.as_mut().data_ref_mut()) } + assert!(!bitmap.is_null()); + 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 c32ce78..f17723b 100644 --- a/src/bitvec.rs +++ b/src/bitvec.rs @@ -13,7 +13,19 @@ use std::ptr::NonNull; /// sp_bitvec_set(vec, 5, true); /// sp_bitvec_free(vec); /// ``` -pub struct SPBitVec(pub(crate) servicepoint::BitVecU8Msb0); +pub struct SPBitVec(servicepoint::BitVec); + +impl From for SPBitVec { + fn from(actual: servicepoint::BitVec) -> Self { + Self(actual) + } +} + +impl From for servicepoint::BitVec { + fn from(value: SPBitVec) -> Self { + value.0 + } +} impl Clone for SPBitVec { fn clone(&self) -> Self { @@ -41,8 +53,7 @@ impl Clone for SPBitVec { /// by explicitly calling `sp_bitvec_free`. #[no_mangle] pub unsafe extern "C" fn sp_bitvec_new(size: usize) -> NonNull { - let result = - Box::new(SPBitVec(servicepoint::BitVecU8Msb0::repeat(false, size))); + let result = Box::new(SPBitVec(servicepoint::BitVec::repeat(false, size))); NonNull::from(Box::leak(result)) } @@ -64,11 +75,12 @@ pub unsafe extern "C" fn sp_bitvec_new(size: usize) -> NonNull { /// by explicitly calling `sp_bitvec_free`. #[no_mangle] pub unsafe extern "C" fn sp_bitvec_load( - data: SPByteSlice, + data: *const u8, + data_length: usize, ) -> NonNull { - let data = unsafe { data.as_slice() }; - let result = - Box::new(SPBitVec(servicepoint::BitVecU8Msb0::from_slice(data))); + assert!(!data.is_null()); + 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)) } @@ -90,9 +102,10 @@ pub unsafe extern "C" fn sp_bitvec_load( /// by explicitly calling `sp_bitvec_free`. #[no_mangle] pub unsafe extern "C" fn sp_bitvec_clone( - bit_vec: NonNull, + bit_vec: *const SPBitVec, ) -> NonNull { - let result = Box::new(unsafe { bit_vec.as_ref().clone() }); + assert!(!bit_vec.is_null()); + let result = Box::new(unsafe { (*bit_vec).clone() }); NonNull::from(Box::leak(result)) } @@ -112,8 +125,9 @@ pub unsafe extern "C" fn sp_bitvec_clone( /// /// [SPCommand]: [crate::SPCommand] #[no_mangle] -pub unsafe extern "C" fn sp_bitvec_free(bit_vec: NonNull) { - _ = unsafe { Box::from_raw(bit_vec.as_ptr()) }; +pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) { + assert!(!bit_vec.is_null()); + _ = unsafe { Box::from_raw(bit_vec) }; } /// Gets the value of a bit from the [SPBitVec]. @@ -138,10 +152,11 @@ pub unsafe extern "C" fn sp_bitvec_free(bit_vec: NonNull) { /// - `bit_vec` is not written to concurrently #[no_mangle] pub unsafe extern "C" fn sp_bitvec_get( - bit_vec: NonNull, + bit_vec: *const SPBitVec, index: usize, ) -> bool { - unsafe { *bit_vec.as_ref().0.get(index).unwrap() } + assert!(!bit_vec.is_null()); + unsafe { *(*bit_vec).0.get(index).unwrap() } } /// Sets the value of a bit in the [SPBitVec]. @@ -165,11 +180,12 @@ pub unsafe extern "C" fn sp_bitvec_get( /// - `bit_vec` is not written to or read from concurrently #[no_mangle] pub unsafe extern "C" fn sp_bitvec_set( - bit_vec: NonNull, + bit_vec: *mut SPBitVec, index: usize, value: bool, ) { - unsafe { (*bit_vec.as_ptr()).0.set(index, value) } + assert!(!bit_vec.is_null()); + unsafe { (*bit_vec).0.set(index, value) } } /// Sets the value of all bits in the [SPBitVec]. @@ -190,11 +206,9 @@ pub unsafe extern "C" fn sp_bitvec_set( /// - `bit_vec` points to a valid [SPBitVec] /// - `bit_vec` is not written to or read from concurrently #[no_mangle] -pub unsafe extern "C" fn sp_bitvec_fill( - bit_vec: NonNull, - value: bool, -) { - unsafe { (*bit_vec.as_ptr()).0.fill(value) } +pub unsafe extern "C" fn sp_bitvec_fill(bit_vec: *mut SPBitVec, value: bool) { + assert!(!bit_vec.is_null()); + unsafe { (*bit_vec).0.fill(value) } } /// Gets the length of the [SPBitVec] in bits. @@ -213,8 +227,9 @@ pub unsafe extern "C" fn sp_bitvec_fill( /// /// - `bit_vec` points to a valid [SPBitVec] #[no_mangle] -pub unsafe extern "C" fn sp_bitvec_len(bit_vec: NonNull) -> usize { - unsafe { bit_vec.as_ref().0.len() } +pub unsafe extern "C" fn sp_bitvec_len(bit_vec: *const SPBitVec) -> usize { + assert!(!bit_vec.is_null()); + unsafe { (*bit_vec).0.len() } } /// Returns true if length is 0. @@ -233,10 +248,9 @@ pub unsafe extern "C" fn sp_bitvec_len(bit_vec: NonNull) -> usize { /// /// - `bit_vec` points to a valid [SPBitVec] #[no_mangle] -pub unsafe extern "C" fn sp_bitvec_is_empty( - bit_vec: NonNull, -) -> bool { - unsafe { bit_vec.as_ref().0.is_empty() } +pub unsafe extern "C" fn sp_bitvec_is_empty(bit_vec: *const SPBitVec) -> bool { + assert!(!bit_vec.is_null()); + unsafe { (*bit_vec).0.is_empty() } } /// Gets an unsafe reference to the data of the [SPBitVec] instance. @@ -258,7 +272,12 @@ pub unsafe extern "C" fn sp_bitvec_is_empty( /// - the returned memory range is never accessed concurrently, either via the [SPBitVec] or directly #[no_mangle] pub unsafe extern "C" fn sp_bitvec_unsafe_data_ref( - bit_vec: NonNull, + bit_vec: *mut SPBitVec, ) -> SPByteSlice { - unsafe { SPByteSlice::from_slice((*bit_vec.as_ptr()).0.as_raw_mut_slice()) } + assert!(!bit_vec.is_null()); + 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 c6abbb4..97dce2c 100644 --- a/src/brightness_grid.rs +++ b/src/brightness_grid.rs @@ -1,26 +1,9 @@ //! C functions for interacting with [SPBrightnessGrid]s //! //! prefix `sp_brightness_grid_` -//! -//! -//! A grid containing brightness values. -//! -//! # Examples -//! ```C -//! SPConnection connection = sp_connection_open("127.0.0.1:2342"); -//! if (connection == NULL) -//! return 1; -//! -//! SPBrightnessGrid grid = sp_brightness_grid_new(2, 2); -//! sp_brightness_grid_set(grid, 0, 0, 0); -//! sp_brightness_grid_set(grid, 1, 1, 10); -//! -//! SPCommand command = sp_command_char_brightness(grid); -//! sp_connection_free(connection); -//! ``` use crate::SPByteSlice; -use servicepoint::{BrightnessGrid, DataRef, Grid}; +use servicepoint::{DataRef, Grid}; use std::convert::Into; use std::mem::transmute; use std::ptr::NonNull; @@ -32,6 +15,24 @@ pub const SP_BRIGHTNESS_MAX: u8 = 11; /// Count of possible brightness values pub const SP_BRIGHTNESS_LEVELS: u8 = 12; +/// A grid containing brightness values. +/// +/// # Examples +/// ```C +/// SPConnection connection = sp_connection_open("127.0.0.1:2342"); +/// if (connection == NULL) +/// return 1; +/// +/// SPBrightnessGrid grid = sp_brightness_grid_new(2, 2); +/// sp_brightness_grid_set(grid, 0, 0, 0); +/// sp_brightness_grid_set(grid, 1, 1, 10); +/// +/// SPCommand command = sp_command_char_brightness(grid); +/// sp_connection_free(connection); +/// ``` +#[derive(Clone)] +pub struct SPBrightnessGrid(pub(crate) servicepoint::BrightnessGrid); + /// Creates a new [SPBrightnessGrid] with the specified dimensions. /// /// returns: [SPBrightnessGrid] initialized to 0. Will never return NULL. @@ -46,8 +47,10 @@ pub const SP_BRIGHTNESS_LEVELS: u8 = 12; pub unsafe extern "C" fn sp_brightness_grid_new( width: usize, height: usize, -) -> NonNull { - let result = Box::new(BrightnessGrid::new(width, height)); +) -> NonNull { + let result = Box::new(SPBrightnessGrid(servicepoint::BrightnessGrid::new( + width, height, + ))); NonNull::from(Box::leak(result)) } @@ -72,15 +75,17 @@ pub unsafe extern "C" fn sp_brightness_grid_new( pub unsafe extern "C" fn sp_brightness_grid_load( width: usize, height: usize, - data: SPByteSlice, -) -> *mut BrightnessGrid { - let data = unsafe { data.as_slice() }; + data: *const u8, + data_length: usize, +) -> *mut SPBrightnessGrid { + assert!(!data.is_null()); + 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) = BrightnessGrid::try_from(grid) { - Box::leak(Box::new(grid)) + if let Ok(grid) = servicepoint::BrightnessGrid::try_from(grid) { + Box::leak(Box::new(SPBrightnessGrid(grid))) } else { std::ptr::null_mut() } @@ -108,9 +113,10 @@ pub unsafe extern "C" fn sp_brightness_grid_load( /// by explicitly calling `sp_brightness_grid_free`. #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_clone( - brightness_grid: NonNull, -) -> NonNull { - let result = Box::new(unsafe { brightness_grid.as_ref().clone() }); + brightness_grid: *const SPBrightnessGrid, +) -> NonNull { + assert!(!brightness_grid.is_null()); + let result = Box::new(unsafe { (*brightness_grid).clone() }); NonNull::from(Box::leak(result)) } @@ -135,9 +141,10 @@ pub unsafe extern "C" fn sp_brightness_grid_clone( /// [SPCommand]: [crate::SPCommand] #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_free( - brightness_grid: NonNull, + brightness_grid: *mut SPBrightnessGrid, ) { - _ = unsafe { Box::from_raw(brightness_grid.as_ptr()) }; + assert!(!brightness_grid.is_null()); + _ = unsafe { Box::from_raw(brightness_grid) }; } /// Gets the current value at the specified position. @@ -162,11 +169,12 @@ pub unsafe extern "C" fn sp_brightness_grid_free( /// - `brightness_grid` is not written to concurrently #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_get( - brightness_grid: NonNull, + brightness_grid: *const SPBrightnessGrid, x: usize, y: usize, ) -> u8 { - unsafe { brightness_grid.as_ref().get(x, y) }.into() + assert!(!brightness_grid.is_null()); + unsafe { (*brightness_grid).0.get(x, y) }.into() } /// Sets the value of the specified position in the [SPBrightnessGrid]. @@ -193,14 +201,15 @@ pub unsafe extern "C" fn sp_brightness_grid_get( /// - `brightness_grid` is not written to or read from concurrently #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_set( - brightness_grid: NonNull, + brightness_grid: *mut SPBrightnessGrid, x: usize, y: usize, value: u8, ) { + assert!(!brightness_grid.is_null()); let brightness = servicepoint::Brightness::try_from(value) .expect("invalid brightness value"); - unsafe { (*brightness_grid.as_ptr()).set(x, y, brightness) }; + unsafe { (*brightness_grid).0.set(x, y, brightness) }; } /// Sets the value of all cells in the [SPBrightnessGrid]. @@ -223,12 +232,13 @@ pub unsafe extern "C" fn sp_brightness_grid_set( /// - `brightness_grid` is not written to or read from concurrently #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_fill( - brightness_grid: NonNull, + brightness_grid: *mut SPBrightnessGrid, value: u8, ) { + assert!(!brightness_grid.is_null()); let brightness = servicepoint::Brightness::try_from(value) .expect("invalid brightness value"); - unsafe { (*brightness_grid.as_ptr()).fill(brightness) }; + unsafe { (*brightness_grid).0.fill(brightness) }; } /// Gets the width of the [SPBrightnessGrid] instance. @@ -250,9 +260,10 @@ pub unsafe extern "C" fn sp_brightness_grid_fill( /// - `brightness_grid` points to a valid [SPBrightnessGrid] #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_width( - brightness_grid: NonNull, + brightness_grid: *const SPBrightnessGrid, ) -> usize { - unsafe { brightness_grid.as_ref().width() } + assert!(!brightness_grid.is_null()); + unsafe { (*brightness_grid).0.width() } } /// Gets the height of the [SPBrightnessGrid] instance. @@ -274,9 +285,10 @@ pub unsafe extern "C" fn sp_brightness_grid_width( /// - `brightness_grid` points to a valid [SPBrightnessGrid] #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_height( - brightness_grid: NonNull, + brightness_grid: *const SPBrightnessGrid, ) -> usize { - unsafe { brightness_grid.as_ref().height() } + assert!(!brightness_grid.is_null()); + unsafe { (*brightness_grid).0.height() } } /// Gets an unsafe reference to the data of the [SPBrightnessGrid] instance. @@ -300,10 +312,15 @@ pub unsafe extern "C" fn sp_brightness_grid_height( /// - the returned memory range is never accessed concurrently, either via the [SPBrightnessGrid] or directly #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref( - brightness_grid: NonNull, + brightness_grid: *mut SPBrightnessGrid, ) -> SPByteSlice { - assert_eq!(size_of::(), 1); - let data = unsafe { (*brightness_grid.as_ptr()).data_ref_mut() }; + assert!(!brightness_grid.is_null()); + assert_eq!(core::mem::size_of::(), 1); + let data = unsafe { (*brightness_grid).0.data_ref_mut() }; // this assumes more about the memory layout than rust guarantees. yikes! - unsafe { SPByteSlice::from_slice(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/byte_slice.rs b/src/byte_slice.rs index 066a405..678a5d7 100644 --- a/src/byte_slice.rs +++ b/src/byte_slice.rs @@ -2,6 +2,7 @@ use std::ptr::NonNull; +#[repr(C)] /// Represents a span of memory (`&mut [u8]` ) as a struct usable by C code. /// /// You should not create an instance of this type in your C code. @@ -15,29 +16,9 @@ use std::ptr::NonNull; /// the function returning this type. /// - an instance of this created from C is never passed to a consuming function, as the rust code /// will try to free the memory of a potentially separate allocator. -#[repr(C)] pub struct SPByteSlice { /// The start address of the memory pub start: NonNull, /// The amount of memory in bytes pub length: usize, } - -impl SPByteSlice { - pub(crate) unsafe fn as_slice(&self) -> &[u8] { - unsafe { std::slice::from_raw_parts(self.start.as_ptr(), self.length) } - } - - pub(crate) unsafe fn as_slice_mut(&self) -> &mut [u8] { - unsafe { - std::slice::from_raw_parts_mut(self.start.as_ptr(), self.length) - } - } - - pub(crate) unsafe fn from_slice(slice: &mut [u8]) -> Self { - Self { - start: NonNull::new(slice.as_mut_ptr()).unwrap(), - length: slice.len(), - } - } -} diff --git a/src/char_grid.rs b/src/char_grid.rs index a845f4e..5ed97c2 100644 --- a/src/char_grid.rs +++ b/src/char_grid.rs @@ -1,27 +1,33 @@ //! C functions for interacting with [SPCharGrid]s //! //! prefix `sp_char_grid_` -//! -//! A C-wrapper for grid containing UTF-8 characters. -//! -//! As the rust [char] type is not FFI-safe, characters are passed in their UTF-32 form as 32bit unsigned integers. -//! -//! The encoding is enforced in most cases by the rust standard library -//! and will panic when provided with illegal characters. -//! -//! # Examples -//! -//! ```C -//! CharGrid grid = sp_char_grid_new(4, 3); -//! sp_char_grid_fill(grid, '?'); -//! sp_char_grid_set(grid, 0, 0, '!'); -//! sp_char_grid_free(grid); -//! ``` -use crate::SPByteSlice; -use servicepoint::{CharGrid, Grid}; +use servicepoint::Grid; use std::ptr::NonNull; +/// A C-wrapper for grid containing UTF-8 characters. +/// +/// As the rust [char] type is not FFI-safe, characters are passed in their UTF-32 form as 32bit unsigned integers. +/// +/// The encoding is enforced in most cases by the rust standard library +/// and will panic when provided with illegal characters. +/// +/// # Examples +/// +/// ```C +/// CharGrid grid = sp_char_grid_new(4, 3); +/// sp_char_grid_fill(grid, '?'); +/// sp_char_grid_set(grid, 0, 0, '!'); +/// sp_char_grid_free(grid); +/// ``` +pub struct SPCharGrid(pub(crate) servicepoint::CharGrid); + +impl Clone for SPCharGrid { + fn clone(&self) -> Self { + SPCharGrid(self.0.clone()) + } +} + /// Creates a new [SPCharGrid] with the specified dimensions. /// /// returns: [SPCharGrid] initialized to 0. Will never return NULL. @@ -36,8 +42,9 @@ use std::ptr::NonNull; pub unsafe extern "C" fn sp_char_grid_new( width: usize, height: usize, -) -> NonNull { - let result = Box::new(CharGrid::new(width, height)); +) -> NonNull { + let result = + Box::new(SPCharGrid(servicepoint::CharGrid::new(width, height))); NonNull::from(Box::leak(result)) } @@ -63,12 +70,15 @@ pub unsafe extern "C" fn sp_char_grid_new( pub unsafe extern "C" fn sp_char_grid_load( width: usize, height: usize, - data: SPByteSlice, -) -> NonNull { - let data = unsafe { data.as_slice() }; - // TODO remove unwrap - let result = - Box::new(CharGrid::load_utf8(width, height, data.to_vec()).unwrap()); + data: *const u8, + data_length: usize, +) -> NonNull { + assert!(data.is_null()); + 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(), + )); NonNull::from(Box::leak(result)) } @@ -90,9 +100,10 @@ pub unsafe extern "C" fn sp_char_grid_load( /// by explicitly calling `sp_char_grid_free`. #[no_mangle] pub unsafe extern "C" fn sp_char_grid_clone( - char_grid: NonNull, -) -> NonNull { - let result = Box::new(unsafe { char_grid.as_ref().clone() }); + char_grid: *const SPCharGrid, +) -> NonNull { + assert!(!char_grid.is_null()); + let result = Box::new(unsafe { (*char_grid).clone() }); NonNull::from(Box::leak(result)) } @@ -112,8 +123,9 @@ pub unsafe extern "C" fn sp_char_grid_clone( /// /// [SPCommand]: [crate::SPCommand] #[no_mangle] -pub unsafe extern "C" fn sp_char_grid_free(char_grid: NonNull) { - _ = unsafe { Box::from_raw(char_grid.as_ptr()) }; +pub unsafe extern "C" fn sp_char_grid_free(char_grid: *mut SPCharGrid) { + assert!(!char_grid.is_null()); + _ = unsafe { Box::from_raw(char_grid) }; } /// Gets the current value at the specified position. @@ -136,11 +148,12 @@ pub unsafe extern "C" fn sp_char_grid_free(char_grid: NonNull) { /// - `char_grid` is not written to concurrently #[no_mangle] pub unsafe extern "C" fn sp_char_grid_get( - char_grid: NonNull, + char_grid: *const SPCharGrid, x: usize, y: usize, ) -> u32 { - unsafe { char_grid.as_ref().get(x, y) as u32 } + assert!(!char_grid.is_null()); + unsafe { (*char_grid).0.get(x, y) as u32 } } /// Sets the value of the specified position in the [SPCharGrid]. @@ -168,12 +181,13 @@ pub unsafe extern "C" fn sp_char_grid_get( /// [SPBitVec]: [crate::SPBitVec] #[no_mangle] pub unsafe extern "C" fn sp_char_grid_set( - char_grid: NonNull, + char_grid: *mut SPCharGrid, x: usize, y: usize, value: u32, ) { - unsafe { (*char_grid.as_ptr()).set(x, y, char::from_u32(value).unwrap()) }; + assert!(!char_grid.is_null()); + unsafe { (*char_grid).0.set(x, y, char::from_u32(value).unwrap()) }; } /// Sets the value of all cells in the [SPCharGrid]. @@ -195,10 +209,11 @@ pub unsafe extern "C" fn sp_char_grid_set( /// - `char_grid` is not written to or read from concurrently #[no_mangle] pub unsafe extern "C" fn sp_char_grid_fill( - char_grid: NonNull, + char_grid: *mut SPCharGrid, value: u32, ) { - unsafe { (*char_grid.as_ptr()).fill(char::from_u32(value).unwrap()) }; + assert!(!char_grid.is_null()); + unsafe { (*char_grid).0.fill(char::from_u32(value).unwrap()) }; } /// Gets the width of the [SPCharGrid] instance. @@ -218,9 +233,10 @@ pub unsafe extern "C" fn sp_char_grid_fill( /// - `char_grid` points to a valid [SPCharGrid] #[no_mangle] pub unsafe extern "C" fn sp_char_grid_width( - char_grid: NonNull, + char_grid: *const SPCharGrid, ) -> usize { - unsafe { char_grid.as_ref().width() } + assert!(!char_grid.is_null()); + unsafe { (*char_grid).0.width() } } /// Gets the height of the [SPCharGrid] instance. @@ -240,7 +256,8 @@ pub unsafe extern "C" fn sp_char_grid_width( /// - `char_grid` points to a valid [SPCharGrid] #[no_mangle] pub unsafe extern "C" fn sp_char_grid_height( - char_grid: NonNull, + char_grid: *const SPCharGrid, ) -> usize { - unsafe { char_grid.as_ref().height() } + assert!(!char_grid.is_null()); + unsafe { (*char_grid).0.height() } } diff --git a/src/command.rs b/src/command.rs index eccac1b..8bfaee3 100644 --- a/src/command.rs +++ b/src/command.rs @@ -2,11 +2,11 @@ //! //! prefix `sp_command_` -use crate::SPBitVec; -use servicepoint::{ - BinaryOperation, Bitmap, BrightnessGrid, CharGrid, CompressionCode, - Cp437Grid, GlobalBrightnessCommand, Packet, TypedCommand, +use crate::{ + SPBitVec, SPBitmap, SPBrightnessGrid, SPCharGrid, SPCompressionCode, + SPCp437Grid, SPPacket, }; +use servicepoint::{BinaryOperation, GlobalBrightnessCommand}; use std::ptr::NonNull; /// A low-level display command. @@ -23,6 +23,13 @@ use std::ptr::NonNull; /// ``` /// /// [SPConnection]: [crate::SPConnection] +pub struct SPCommand(pub(crate) servicepoint::TypedCommand); + +impl Clone for SPCommand { + fn clone(&self) -> Self { + SPCommand(self.0.clone()) + } +} /// Tries to turn a [SPPacket] into a [SPCommand]. /// @@ -45,12 +52,12 @@ use std::ptr::NonNull; /// by explicitly calling `sp_command_free`. #[no_mangle] pub unsafe extern "C" fn sp_command_try_from_packet( - packet: NonNull, -) -> *mut TypedCommand { - let packet = *unsafe { Box::from_raw(packet.as_ptr()) }; - match servicepoint::TypedCommand::try_from(packet) { + packet: *mut SPPacket, +) -> *mut SPCommand { + 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(command)), + Ok(command) => Box::into_raw(Box::new(SPCommand(command))), } } @@ -72,9 +79,10 @@ pub unsafe extern "C" fn sp_command_try_from_packet( /// by explicitly calling `sp_command_free`. #[no_mangle] pub unsafe extern "C" fn sp_command_clone( - command: NonNull, -) -> NonNull { - let result = Box::new(unsafe { command.as_ref().clone() }); + command: *const SPCommand, +) -> NonNull { + assert!(!command.is_null()); + let result = Box::new(unsafe { (*command).clone() }); NonNull::from(Box::leak(result)) } @@ -97,8 +105,8 @@ pub unsafe extern "C" fn sp_command_clone( /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. #[no_mangle] -pub unsafe extern "C" fn sp_command_clear() -> NonNull { - let result = Box::new(servicepoint::ClearCommand.into()); +pub unsafe extern "C" fn sp_command_clear() -> NonNull { + let result = Box::new(SPCommand(servicepoint::ClearCommand.into())); NonNull::from(Box::leak(result)) } @@ -115,8 +123,8 @@ pub unsafe extern "C" fn sp_command_clear() -> NonNull { /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. #[no_mangle] -pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull { - let result = Box::new(servicepoint::HardResetCommand.into()); +pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull { + let result = Box::new(SPCommand(servicepoint::HardResetCommand.into())); NonNull::from(Box::leak(result)) } @@ -131,8 +139,8 @@ pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull { /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. #[no_mangle] -pub unsafe extern "C" fn sp_command_fade_out() -> NonNull { - let result = Box::new(servicepoint::FadeOutCommand.into()); +pub unsafe extern "C" fn sp_command_fade_out() -> NonNull { + let result = Box::new(SPCommand(servicepoint::FadeOutCommand.into())); NonNull::from(Box::leak(result)) } @@ -153,10 +161,11 @@ pub unsafe extern "C" fn sp_command_fade_out() -> NonNull { #[no_mangle] pub unsafe extern "C" fn sp_command_brightness( brightness: u8, -) -> NonNull { +) -> NonNull { let brightness = servicepoint::Brightness::try_from(brightness) .expect("invalid brightness"); - let result = Box::new(GlobalBrightnessCommand::from(brightness).into()); + let result = + Box::new(SPCommand(GlobalBrightnessCommand::from(brightness).into())); NonNull::from(Box::leak(result)) } @@ -182,16 +191,17 @@ pub unsafe extern "C" fn sp_command_brightness( pub unsafe extern "C" fn sp_command_char_brightness( x: usize, y: usize, - grid: NonNull, -) -> NonNull { - let grid = unsafe { *Box::from_raw(grid.as_ptr()) }; - let result = Box::new( + grid: *mut SPBrightnessGrid, +) -> NonNull { + assert!(!grid.is_null()); + let byte_grid = unsafe { *Box::from_raw(grid) }; + let result = Box::new(SPCommand( servicepoint::BrightnessGridCommand { origin: servicepoint::Origin::new(x, y), - grid, + grid: byte_grid.0, } .into(), - ); + )); NonNull::from(Box::leak(result)) } @@ -223,9 +233,9 @@ pub unsafe extern "C" fn sp_command_char_brightness( #[no_mangle] pub unsafe extern "C" fn sp_command_bitmap_linear( offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { + bit_vec: *mut SPBitVec, + compression: SPCompressionCode, +) -> *mut SPCommand { unsafe { sp_command_bitmap_linear_internal( offset, @@ -264,9 +274,9 @@ pub unsafe extern "C" fn sp_command_bitmap_linear( #[no_mangle] pub unsafe extern "C" fn sp_command_bitmap_linear_and( offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { + bit_vec: *mut SPBitVec, + compression: SPCompressionCode, +) -> *mut SPCommand { unsafe { sp_command_bitmap_linear_internal( offset, @@ -305,9 +315,9 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_and( #[no_mangle] pub unsafe extern "C" fn sp_command_bitmap_linear_or( offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { + bit_vec: *mut SPBitVec, + compression: SPCompressionCode, +) -> *mut SPCommand { unsafe { sp_command_bitmap_linear_internal( offset, @@ -346,9 +356,9 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_or( #[no_mangle] pub unsafe extern "C" fn sp_command_bitmap_linear_xor( offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { + bit_vec: *mut SPBitVec, + compression: SPCompressionCode, +) -> *mut SPCommand { unsafe { sp_command_bitmap_linear_internal( offset, @@ -362,22 +372,25 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_xor( #[inline] unsafe fn sp_command_bitmap_linear_internal( offset: usize, - bit_vec: NonNull, - compression: CompressionCode, + bit_vec: *mut SPBitVec, + compression: SPCompressionCode, operation: BinaryOperation, -) -> *mut TypedCommand { - let bit_vec = unsafe { *Box::from_raw(bit_vec.as_ptr()) }; +) -> *mut SPCommand { + assert!(!bit_vec.is_null()); + 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 = servicepoint::BitVecCommand { - offset, - operation, - bitvec: bit_vec.0, - compression, - } - .into(); + let command = SPCommand( + servicepoint::BitVecCommand { + offset, + operation, + bitvec: bit_vec.into(), + compression, + } + .into(), + ); Box::leak(Box::new(command)) } @@ -403,16 +416,17 @@ unsafe fn sp_command_bitmap_linear_internal( pub unsafe extern "C" fn sp_command_cp437_data( x: usize, y: usize, - grid: NonNull, -) -> NonNull { - let grid = *unsafe { Box::from_raw(grid.as_ptr()) }; - let result = Box::new( + grid: *mut SPCp437Grid, +) -> NonNull { + assert!(!grid.is_null()); + let grid = *unsafe { Box::from_raw(grid) }; + let result = Box::new(SPCommand( servicepoint::Cp437GridCommand { origin: servicepoint::Origin::new(x, y), - grid, + grid: grid.0, } .into(), - ); + )); NonNull::from(Box::leak(result)) } @@ -438,16 +452,17 @@ pub unsafe extern "C" fn sp_command_cp437_data( pub unsafe extern "C" fn sp_command_utf8_data( x: usize, y: usize, - grid: NonNull, -) -> NonNull { - let grid = unsafe { *Box::from_raw(grid.as_ptr()) }; - let result = Box::new( + grid: *mut SPCharGrid, +) -> NonNull { + assert!(!grid.is_null()); + let grid = unsafe { *Box::from_raw(grid) }; + let result = Box::new(SPCommand( servicepoint::CharGridCommand { origin: servicepoint::Origin::new(x, y), - grid, + grid: grid.0, } .into(), - ); + )); NonNull::from(Box::leak(result)) } @@ -475,20 +490,23 @@ pub unsafe extern "C" fn sp_command_utf8_data( pub unsafe extern "C" fn sp_command_bitmap_linear_win( x: usize, y: usize, - bitmap: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { - let bitmap = unsafe { *Box::from_raw(bitmap.as_ptr()) }; + bitmap: *mut SPBitmap, + compression: SPCompressionCode, +) -> *mut SPCommand { + assert!(!bitmap.is_null()); + 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 = servicepoint::BitmapCommand { - origin: servicepoint::Origin::new(x, y), - bitmap, - compression, - } - .into(); + let command = SPCommand( + servicepoint::BitmapCommand { + origin: servicepoint::Origin::new(x, y), + bitmap, + compression, + } + .into(), + ); Box::leak(Box::new(command)) } @@ -513,6 +531,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_win( /// - `command` is not used concurrently or after this call /// - `command` was not passed to another consuming function, e.g. to create a [SPPacket] #[no_mangle] -pub unsafe extern "C" fn sp_command_free(command: NonNull) { - _ = unsafe { Box::from_raw(command.as_ptr()) }; +pub unsafe extern "C" fn sp_command_free(command: *mut SPCommand) { + assert!(!command.is_null()); + _ = unsafe { Box::from_raw(command) }; } diff --git a/src/connection.rs b/src/connection.rs index 1705538..9e484ae 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,20 +1,21 @@ //! C functions for interacting with [SPConnection]s //! //! prefix `sp_connection_` -//! -//! 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()); -//! ``` -use servicepoint::{Connection, Packet, TypedCommand, UdpConnection}; +use crate::{SPCommand, SPPacket}; +use servicepoint::Connection; use std::ffi::{c_char, CStr}; -use std::ptr::NonNull; + +/// 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()); +/// ``` +pub struct SPConnection(pub(crate) servicepoint::UdpConnection); /// Creates a new instance of [SPConnection]. /// @@ -32,31 +33,20 @@ use std::ptr::NonNull; /// by explicitly calling `sp_connection_free`. #[no_mangle] pub unsafe extern "C" fn sp_connection_open( - host: NonNull, -) -> *mut UdpConnection { - let host = unsafe { CStr::from_ptr(host.as_ptr()) } + host: *const c_char, +) -> *mut SPConnection { + assert!(!host.is_null()); + let host = unsafe { CStr::from_ptr(host) } .to_str() .expect("Bad encoding"); - let connection = match UdpConnection::open(host) { + let connection = match servicepoint::UdpConnection::open(host) { Err(_) => return std::ptr::null_mut(), Ok(value) => value, }; - Box::into_raw(Box::new(connection)) + Box::into_raw(Box::new(SPConnection(connection))) } -//#[no_mangle] -//pub unsafe extern "C" fn sp_connection_open_ipv4( -// host: SocketAddrV4, -//) -> *mut SPConnection { -// 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 [SPUdpConnection] for testing that does not actually send anything. // /// // /// returns: a new instance. Will never return NULL. @@ -93,11 +83,13 @@ pub unsafe extern "C" fn sp_connection_open( /// - `packet` is not used concurrently or after this call #[no_mangle] pub unsafe extern "C" fn sp_connection_send_packet( - connection: NonNull, - packet: NonNull, + connection: *const SPConnection, + packet: *mut SPPacket, ) -> bool { - let packet = unsafe { Box::from_raw(packet.as_ptr()) }; - unsafe { connection.as_ref().send(*packet) }.is_ok() + assert!(!connection.is_null()); + assert!(!packet.is_null()); + let packet = unsafe { Box::from_raw(packet) }; + unsafe { (*connection).0.send((*packet).0) }.is_ok() } /// Sends a [SPCommand] to the display using the [SPConnection]. @@ -120,11 +112,13 @@ pub unsafe extern "C" fn sp_connection_send_packet( /// - `command` is not used concurrently or after this call #[no_mangle] pub unsafe extern "C" fn sp_connection_send_command( - connection: NonNull, - command: NonNull, + connection: *const SPConnection, + command: *mut SPCommand, ) -> bool { - let command = *unsafe { Box::from_raw(command.as_ptr()) }; - unsafe { connection.as_ref().send(command) }.is_ok() + assert!(!connection.is_null()); + assert!(!command.is_null()); + let command = (*unsafe { Box::from_raw(command) }).0; + unsafe { (*connection).0.send(command) }.is_ok() } /// Closes and deallocates a [SPConnection]. @@ -140,8 +134,7 @@ pub unsafe extern "C" fn sp_connection_send_command( /// - `connection` points to a valid [SPConnection] /// - `connection` is not used concurrently or after this call #[no_mangle] -pub unsafe extern "C" fn sp_connection_free( - connection: NonNull, -) { - _ = unsafe { Box::from_raw(connection.as_ptr()) }; +pub unsafe extern "C" fn sp_connection_free(connection: *mut SPConnection) { + assert!(!connection.is_null()); + _ = unsafe { Box::from_raw(connection) }; } diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 0000000..ad1e77c --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,48 @@ +//! re-exported constants for use in C + +use servicepoint::CompressionCode; +use std::time::Duration; + +/// size of a single tile in one dimension +pub const SP_TILE_SIZE: usize = 8; + +/// Display tile count in the x-direction +pub const SP_TILE_WIDTH: usize = 56; + +/// Display tile count in the y-direction +pub const SP_TILE_HEIGHT: usize = 20; + +/// Display width in pixels +pub const SP_PIXEL_WIDTH: usize = SP_TILE_WIDTH * SP_TILE_SIZE; + +/// Display height in pixels +pub const SP_PIXEL_HEIGHT: usize = SP_TILE_HEIGHT * SP_TILE_SIZE; + +/// pixel count on whole screen +pub const SP_PIXEL_COUNT: usize = SP_PIXEL_WIDTH * SP_PIXEL_HEIGHT; + +/// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets. +pub const SP_FRAME_PACING_MS: u128 = Duration::from_millis(30).as_millis(); + +/// Specifies the kind of compression to use. +#[repr(u16)] +pub enum SPCompressionCode { + /// no compression + Uncompressed = 0x0, + /// compress using flate2 with zlib header + Zlib = 0x677a, + /// compress using bzip2 + Bzip2 = 0x627a, + /// compress using lzma + Lzma = 0x6c7a, + /// compress using Zstandard + Zstd = 0x7a73, +} + +impl TryFrom for CompressionCode { + type Error = (); + + fn try_from(value: SPCompressionCode) -> Result { + CompressionCode::try_from(value as u16).map_err(|_| ()) + } +} diff --git a/src/cp437_grid.rs b/src/cp437_grid.rs index e635247..89fcffc 100644 --- a/src/cp437_grid.rs +++ b/src/cp437_grid.rs @@ -1,25 +1,31 @@ //! C functions for interacting with [SPCp437Grid]s //! //! prefix `sp_cp437_grid_` -//! -//! -//! A C-wrapper for grid containing codepage 437 characters. -//! -//! The encoding is currently not enforced. -//! -//! # Examples -//! -//! ```C -//! Cp437Grid grid = sp_cp437_grid_new(4, 3); -//! sp_cp437_grid_fill(grid, '?'); -//! sp_cp437_grid_set(grid, 0, 0, '!'); -//! sp_cp437_grid_free(grid); -//! ``` use crate::SPByteSlice; -use servicepoint::{Cp437Grid, DataRef, Grid}; +use servicepoint::{DataRef, Grid}; use std::ptr::NonNull; +/// A C-wrapper for grid containing codepage 437 characters. +/// +/// The encoding is currently not enforced. +/// +/// # Examples +/// +/// ```C +/// Cp437Grid grid = sp_cp437_grid_new(4, 3); +/// sp_cp437_grid_fill(grid, '?'); +/// sp_cp437_grid_set(grid, 0, 0, '!'); +/// sp_cp437_grid_free(grid); +/// ``` +pub struct SPCp437Grid(pub(crate) servicepoint::Cp437Grid); + +impl Clone for SPCp437Grid { + fn clone(&self) -> Self { + SPCp437Grid(self.0.clone()) + } +} + /// Creates a new [SPCp437Grid] with the specified dimensions. /// /// returns: [SPCp437Grid] initialized to 0. Will never return NULL. @@ -34,8 +40,9 @@ use std::ptr::NonNull; pub unsafe extern "C" fn sp_cp437_grid_new( width: usize, height: usize, -) -> NonNull { - let result = Box::new(Cp437Grid::new(width, height)); +) -> NonNull { + let result = + Box::new(SPCp437Grid(servicepoint::Cp437Grid::new(width, height))); NonNull::from(Box::leak(result)) } @@ -60,12 +67,14 @@ pub unsafe extern "C" fn sp_cp437_grid_new( pub unsafe extern "C" fn sp_cp437_grid_load( width: usize, height: usize, - data: SPByteSlice, -) -> *mut Cp437Grid { - let data = unsafe { data.as_slice() }; - let grid = Cp437Grid::load(width, height, data); + data: *const u8, + data_length: usize, +) -> *mut SPCp437Grid { + assert!(data.is_null()); + 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(grid)) + Box::leak(Box::new(SPCp437Grid(grid))) } else { std::ptr::null_mut() } @@ -89,9 +98,10 @@ pub unsafe extern "C" fn sp_cp437_grid_load( /// by explicitly calling `sp_cp437_grid_free`. #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_clone( - cp437_grid: NonNull, -) -> NonNull { - let result = Box::new(unsafe { cp437_grid.as_ref().clone() }); + cp437_grid: *const SPCp437Grid, +) -> NonNull { + assert!(!cp437_grid.is_null()); + let result = Box::new(unsafe { (*cp437_grid).clone() }); NonNull::from(Box::leak(result)) } @@ -111,8 +121,9 @@ pub unsafe extern "C" fn sp_cp437_grid_clone( /// /// [SPCommand]: [crate::SPCommand] #[no_mangle] -pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: NonNull) { - _ = unsafe { Box::from_raw(cp437_grid.as_ptr()) }; +pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) { + assert!(!cp437_grid.is_null()); + _ = unsafe { Box::from_raw(cp437_grid) }; } /// Gets the current value at the specified position. @@ -135,11 +146,12 @@ pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: NonNull) { /// - `cp437_grid` is not written to concurrently #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_get( - cp437_grid: NonNull, + cp437_grid: *const SPCp437Grid, x: usize, y: usize, ) -> u8 { - unsafe { cp437_grid.as_ref().get(x, y) } + assert!(!cp437_grid.is_null()); + unsafe { (*cp437_grid).0.get(x, y) } } /// Sets the value of the specified position in the [SPCp437Grid]. @@ -167,12 +179,13 @@ pub unsafe extern "C" fn sp_cp437_grid_get( /// [SPBitVec]: [crate::SPBitVec] #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_set( - cp437_grid: NonNull, + cp437_grid: *mut SPCp437Grid, x: usize, y: usize, value: u8, ) { - unsafe { (*cp437_grid.as_ptr()).set(x, y, value) }; + assert!(!cp437_grid.is_null()); + unsafe { (*cp437_grid).0.set(x, y, value) }; } /// Sets the value of all cells in the [SPCp437Grid]. @@ -194,10 +207,11 @@ pub unsafe extern "C" fn sp_cp437_grid_set( /// - `cp437_grid` is not written to or read from concurrently #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_fill( - cp437_grid: NonNull, + cp437_grid: *mut SPCp437Grid, value: u8, ) { - unsafe { (*cp437_grid.as_ptr()).fill(value) }; + assert!(!cp437_grid.is_null()); + unsafe { (*cp437_grid).0.fill(value) }; } /// Gets the width of the [SPCp437Grid] instance. @@ -217,9 +231,10 @@ pub unsafe extern "C" fn sp_cp437_grid_fill( /// - `cp437_grid` points to a valid [SPCp437Grid] #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_width( - cp437_grid: NonNull, + cp437_grid: *const SPCp437Grid, ) -> usize { - unsafe { cp437_grid.as_ref().width() } + assert!(!cp437_grid.is_null()); + unsafe { (*cp437_grid).0.width() } } /// Gets the height of the [SPCp437Grid] instance. @@ -239,9 +254,10 @@ pub unsafe extern "C" fn sp_cp437_grid_width( /// - `cp437_grid` points to a valid [SPCp437Grid] #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_height( - cp437_grid: NonNull, + cp437_grid: *const SPCp437Grid, ) -> usize { - unsafe { cp437_grid.as_ref().height() } + assert!(!cp437_grid.is_null()); + unsafe { (*cp437_grid).0.height() } } /// Gets an unsafe reference to the data of the [SPCp437Grid] instance. @@ -261,7 +277,11 @@ pub unsafe extern "C" fn sp_cp437_grid_height( /// - the returned memory range is never accessed concurrently, either via the [SPCp437Grid] or directly #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_unsafe_data_ref( - cp437_grid: NonNull, + cp437_grid: *mut SPCp437Grid, ) -> SPByteSlice { - unsafe { SPByteSlice::from_slice((*cp437_grid.as_ptr()).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/lib.rs b/src/lib.rs index 831daea..887fb40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ pub use crate::byte_slice::*; pub use crate::char_grid::*; pub use crate::command::*; pub use crate::connection::*; +pub use crate::constants::*; pub use crate::cp437_grid::*; pub use crate::packet::*; @@ -42,10 +43,6 @@ mod byte_slice; mod char_grid; mod command; mod connection; +mod constants; mod cp437_grid; mod packet; - -use std::time::Duration; - -/// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets. -pub const SP_FRAME_PACING_MS: u128 = Duration::from_millis(30).as_millis(); diff --git a/src/packet.rs b/src/packet.rs index f8235ab..fd36006 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,14 +1,14 @@ //! C functions for interacting with [SPPacket]s //! //! prefix `sp_packet_` -//! -//! -//! The raw packet -use crate::SPByteSlice; -use servicepoint::{Header, Packet, TypedCommand}; use std::ptr::NonNull; +use crate::SPCommand; + +/// The raw packet +pub struct SPPacket(pub(crate) servicepoint::Packet); + /// Turns a [SPCommand] into a [SPPacket]. /// The [SPCommand] gets consumed. /// @@ -28,11 +28,12 @@ use std::ptr::NonNull; /// by explicitly calling `sp_packet_free`. #[no_mangle] pub unsafe extern "C" fn sp_packet_from_command( - command: NonNull, -) -> *mut Packet { - let command = unsafe { *Box::from_raw(command.as_ptr()) }; - if let Ok(packet) = command.try_into() { - Box::leak(Box::new(packet)) + command: *mut SPCommand, +) -> *mut SPPacket { + assert!(!command.is_null()); + 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() } @@ -55,11 +56,15 @@ pub unsafe extern "C" fn sp_packet_from_command( /// - the returned [SPPacket] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_packet_free`. #[no_mangle] -pub unsafe extern "C" fn sp_packet_try_load(data: SPByteSlice) -> *mut Packet { - let data = unsafe { data.as_slice() }; +pub unsafe extern "C" fn sp_packet_try_load( + data: *const u8, + length: usize, +) -> *mut SPPacket { + assert!(!data.is_null()); + let data = unsafe { std::slice::from_raw_parts(data, length) }; match servicepoint::Packet::try_from(data) { Err(_) => std::ptr::null_mut(), - Ok(packet) => Box::into_raw(Box::new(packet)), + Ok(packet) => Box::into_raw(Box::new(SPPacket(packet))), } } @@ -89,50 +94,36 @@ pub unsafe extern "C" fn sp_packet_try_load(data: SPByteSlice) -> *mut Packet { /// by explicitly calling [sp_packet_free]. #[no_mangle] pub unsafe extern "C" fn sp_packet_from_parts( - header: Header, - payload: *const SPByteSlice, -) -> NonNull { + command_code: u16, + a: u16, + b: u16, + c: u16, + d: u16, + payload: *const u8, + payload_len: usize, +) -> NonNull { + assert_eq!(payload.is_null(), payload_len == 0); + let payload = if payload.is_null() { vec![] } else { - let payload = unsafe { (*payload).as_slice() }; + let payload = + unsafe { std::slice::from_raw_parts(payload, payload_len) }; Vec::from(payload) }; - let packet = Box::new(Packet { header, payload }); - NonNull::from(Box::leak(packet)) -} - -#[no_mangle] -pub unsafe extern "C" fn sp_packet_get_header( - packet: NonNull, -) -> NonNull
{ - NonNull::from(&mut unsafe { (*packet.as_ptr()).header }) -} - -#[no_mangle] -pub unsafe extern "C" fn sp_packet_get_payload( - packet: NonNull, -) -> SPByteSlice { - unsafe { SPByteSlice::from_slice(&mut *(*packet.as_ptr()).payload) } -} - -#[no_mangle] -pub unsafe extern "C" fn sp_packet_set_payload( - packet: NonNull, - data: SPByteSlice, -) { - unsafe { (*packet.as_ptr()).payload = data.as_slice().to_vec() } -} - -#[no_mangle] -pub unsafe extern "C" fn sp_packet_write_to( - packet: NonNull, - buffer: SPByteSlice, -) { - unsafe { - packet.as_ref().serialize_to(buffer.as_slice_mut()); - } + let packet = servicepoint::Packet { + header: servicepoint::Header { + command_code, + a, + b, + c, + d, + }, + payload, + }; + let result = Box::new(SPPacket(packet)); + NonNull::from(Box::leak(result)) } /// Clones a [SPPacket]. @@ -153,9 +144,10 @@ pub unsafe extern "C" fn sp_packet_write_to( /// by explicitly calling `sp_packet_free`. #[no_mangle] pub unsafe extern "C" fn sp_packet_clone( - packet: NonNull, -) -> NonNull { - let result = Box::new(unsafe { packet.as_ref().clone() }); + packet: *const SPPacket, +) -> NonNull { + assert!(!packet.is_null()); + let result = Box::new(SPPacket(unsafe { (*packet).0.clone() })); NonNull::from(Box::leak(result)) } @@ -172,6 +164,7 @@ pub unsafe extern "C" fn sp_packet_clone( /// - `packet` points to a valid [SPPacket] /// - `packet` is not used concurrently or after this call #[no_mangle] -pub unsafe extern "C" fn sp_packet_free(packet: NonNull) { - _ = unsafe { Box::from_raw(packet.as_ptr()) } +pub unsafe extern "C" fn sp_packet_free(packet: *mut SPPacket) { + assert!(!packet.is_null()); + _ = unsafe { Box::from_raw(packet) } }