expose CharGrid to C API
This commit is contained in:
		
							parent
							
								
									4f83aa3d5c
								
							
						
					
					
						commit
						2f2160f246
					
				
					 9 changed files with 676 additions and 22 deletions
				
			
		
							
								
								
									
										10
									
								
								crates/servicepoint/src/bit_vec.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								crates/servicepoint/src/bit_vec.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| /// A byte-packed vector of booleans.
 | ||||
| ///
 | ||||
| /// The implementation is provided by [bitvec].
 | ||||
| /// This is an alias for the specific type of [bitvec::BitVec] used in this crate.
 | ||||
| pub type BitVec = bitvec::BitVec<u8, bitvec::Msb0>; | ||||
| 
 | ||||
| pub mod bitvec { | ||||
|     //! Re-export of the used library [mod@bitvec].
 | ||||
|     pub use bitvec::prelude::*; | ||||
| } | ||||
|  | @ -5,7 +5,18 @@ use ::bitvec::order::Msb0; | |||
| use ::bitvec::prelude::BitSlice; | ||||
| use ::bitvec::slice::IterMut; | ||||
| 
 | ||||
| /// A grid of pixels stored in packed bytes.
 | ||||
| /// 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.
 | ||||
| ///
 | ||||
| /// # Examples
 | ||||
| ///
 | ||||
| /// ```rust
 | ||||
| /// use servicepoint::Bitmap;
 | ||||
| /// let mut bitmap = Bitmap::new(4, 2);
 | ||||
| ///
 | ||||
| /// ```
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| pub struct Bitmap { | ||||
|     width: usize, | ||||
|  | @ -27,7 +38,11 @@ impl Bitmap { | |||
|     ///
 | ||||
|     /// - when the width is not dividable by 8
 | ||||
|     pub fn new(width: usize, height: usize) -> Self { | ||||
|         assert_eq!(width % 8, 0); | ||||
|         assert_eq!( | ||||
|             width % 8, | ||||
|             0, | ||||
|             "width must be a multiple of 8, but is {width}" | ||||
|         ); | ||||
|         Self { | ||||
|             width, | ||||
|             height, | ||||
|  | @ -182,6 +197,26 @@ impl From<Bitmap> for BitVec { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<&ValueGrid<bool>> for Bitmap { | ||||
|     fn from(value: &ValueGrid<bool>) -> Self { | ||||
|         let mut result = Self::new(value.width(), value.height()); | ||||
|         for (mut to, from) in result.iter_mut().zip(value.iter()) { | ||||
|             *to = *from; | ||||
|         } | ||||
|         result | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<&Bitmap> for ValueGrid<bool> { | ||||
|     fn from(value: &Bitmap) -> Self { | ||||
|         let mut result = Self::new(value.width(), value.height()); | ||||
|         for (to, from) in result.iter_mut().zip(value.iter()) { | ||||
|             *to = *from; | ||||
|         } | ||||
|         result | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct IterRows<'t> { | ||||
|     bitmap: &'t Bitmap, | ||||
|     row: usize, | ||||
|  | @ -204,7 +239,7 @@ impl<'t> Iterator for IterRows<'t> { | |||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use crate::{BitVec, Bitmap, DataRef, Grid}; | ||||
|     use crate::{BitVec, Bitmap, DataRef, Grid, ValueGrid}; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn fill() { | ||||
|  | @ -304,4 +339,16 @@ mod tests { | |||
|         let bitvec: BitVec = grid.into(); | ||||
|         assert_eq!(bitvec.as_raw_slice(), [0x80, 0x00]); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn from_bool_grid() { | ||||
|         let original = ValueGrid::load( | ||||
|             8, | ||||
|             1, | ||||
|             &[true, false, true, false, true, false, true, false], | ||||
|         ); | ||||
|         let converted = Bitmap::from(&original); | ||||
|         let reconverted = ValueGrid::from(&converted); | ||||
|         assert_eq!(original, reconverted); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,4 +0,0 @@ | |||
| pub use bitvec::prelude::*; | ||||
| 
 | ||||
| /// An alias for the specific type of [bitvec::prelude::BitVec] used.
 | ||||
| pub type BitVec = bitvec::prelude::BitVec<u8, Msb0>; | ||||
|  | @ -1,2 +1,4 @@ | |||
| /// A 2d grid of bytes - see [crate::ValueGrid].
 | ||||
| pub type ByteGrid = crate::value_grid::ValueGrid<u8>; | ||||
| use crate::ValueGrid; | ||||
| 
 | ||||
| /// A 2d grid of bytes - see [ValueGrid].
 | ||||
| pub type ByteGrid = ValueGrid<u8>; | ||||
|  |  | |||
|  | @ -2,14 +2,17 @@ | |||
| //!
 | ||||
| //! Your starting point is a [Connection] to the display.
 | ||||
| //! With a connection, you can send [Command]s.
 | ||||
| //! When received, the display will update the state of the pixels.
 | ||||
| //! When received, the display will update the state of its pixels.
 | ||||
| //!
 | ||||
| //! # Examples
 | ||||
| //!
 | ||||
| //! ```rust
 | ||||
| //! use servicepoint::{Command, CompressionCode, Grid, Bitmap};
 | ||||
| //! ### Clear display
 | ||||
| //!
 | ||||
| //! let connection = servicepoint::Connection::open("127.0.0.1:2342")
 | ||||
| //! ```rust
 | ||||
| //! use servicepoint::{Connection, Command};
 | ||||
| //!
 | ||||
| //! // establish a connection
 | ||||
| //! let connection = Connection::open("127.0.0.1:2342")
 | ||||
| //!     .expect("connection failed");
 | ||||
| //!
 | ||||
| //!  // turn off all pixels on display
 | ||||
|  | @ -17,6 +20,8 @@ | |||
| //!     .expect("send failed");
 | ||||
| //! ```
 | ||||
| //!
 | ||||
| //! ### Set all pixels to on
 | ||||
| //!
 | ||||
| //! ```rust
 | ||||
| //! # use servicepoint::{Command, CompressionCode, Grid, Bitmap};
 | ||||
| //! # let connection = servicepoint::Connection::open("127.0.0.1:2342").expect("connection failed");
 | ||||
|  | @ -34,9 +39,24 @@ | |||
| //!  // send command to display
 | ||||
| //!  connection.send(command).expect("send failed");
 | ||||
| //! ```
 | ||||
| //!
 | ||||
| //! ### Send text
 | ||||
| //!
 | ||||
| //! ```rust
 | ||||
| //! # use servicepoint::{Command, CompressionCode, Grid, Bitmap, CharGrid};
 | ||||
| //! # let connection = servicepoint::Connection::open("127.0.0.1:2342").expect("connection failed");
 | ||||
| //! // create a text grid
 | ||||
| //! let mut grid = CharGrid::from("Hello\nCCCB?");
 | ||||
| //! // modify the grid
 | ||||
| //! grid.set(grid.width() - 1, 1, '!');
 | ||||
| //! // create the command to send the data
 | ||||
| //! let command = Command::Utf8Data(servicepoint::Origin::ZERO, grid);
 | ||||
| //! // send command to display
 | ||||
| //! connection.send(command).expect("send failed");
 | ||||
| //! ```
 | ||||
| 
 | ||||
| pub use crate::bit_vec::{bitvec, BitVec}; | ||||
| pub use crate::bitmap::Bitmap; | ||||
| pub use crate::bitvec::BitVec; | ||||
| pub use crate::brightness::Brightness; | ||||
| pub use crate::brightness_grid::BrightnessGrid; | ||||
| pub use crate::byte_grid::ByteGrid; | ||||
|  | @ -55,8 +75,8 @@ pub use crate::value_grid::{ | |||
|     IterGridRows, SetValueSeriesError, TryLoadValueGridError, Value, ValueGrid, | ||||
| }; | ||||
| 
 | ||||
| mod bit_vec; | ||||
| mod bitmap; | ||||
| mod bitvec; | ||||
| mod brightness; | ||||
| mod brightness_grid; | ||||
| mod byte_grid; | ||||
|  |  | |||
|  | @ -14,12 +14,12 @@ | |||
| #define SP_BRIGHTNESS_LEVELS 12 | ||||
| 
 | ||||
| /**
 | ||||
|  * see [Brightness::MAX] | ||||
|  * see [servicepoint::Brightness::MAX] | ||||
|  */ | ||||
| #define SP_BRIGHTNESS_MAX 11 | ||||
| 
 | ||||
| /**
 | ||||
|  * see [Brightness::MIN] | ||||
|  * see [servicepoint::Brightness::MIN] | ||||
|  */ | ||||
| #define SP_BRIGHTNESS_MIN 0 | ||||
| 
 | ||||
|  | @ -131,6 +131,25 @@ typedef struct SPBitmap SPBitmap; | |||
|  */ | ||||
| typedef struct SPBrightnessGrid SPBrightnessGrid; | ||||
| 
 | ||||
| /**
 | ||||
|  * 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); | ||||
|  * ``` | ||||
|  */ | ||||
| typedef struct SPCharGrid SPCharGrid; | ||||
| 
 | ||||
| /**
 | ||||
|  * A low-level display command. | ||||
|  * | ||||
|  | @ -367,6 +386,20 @@ SPBitmap *sp_bitmap_load(size_t width, | |||
| SPBitmap *sp_bitmap_new(size_t width, | ||||
|                         size_t height); | ||||
| 
 | ||||
| /**
 | ||||
|  * Creates a new [SPBitmap] with a size matching the screen. | ||||
|  * | ||||
|  * returns: [SPBitmap] initialized to all pixels off. Will never return NULL. | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - the returned instance is freed in some way, either by using a consuming function or | ||||
|  *   by explicitly calling [sp_bitmap_free]. | ||||
|  */ | ||||
| SPBitmap *sp_bitmap_new_screen_sized(void); | ||||
| 
 | ||||
| /**
 | ||||
|  * Sets the value of the specified position in the [SPBitmap]. | ||||
|  * | ||||
|  | @ -865,6 +898,196 @@ SPByteSlice sp_brightness_grid_unsafe_data_ref(SPBrightnessGrid *brightness_grid | |||
|  */ | ||||
| size_t sp_brightness_grid_width(const SPBrightnessGrid *brightness_grid); | ||||
| 
 | ||||
| /**
 | ||||
|  * Clones a [SPCharGrid]. | ||||
|  * | ||||
|  * Will never return NULL. | ||||
|  * | ||||
|  * # Panics | ||||
|  * | ||||
|  * - when `char_grid` is NULL | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - `char_grid` points to a valid [SPCharGrid] | ||||
|  * - `char_grid` is not written to concurrently | ||||
|  * - the returned instance is freed in some way, either by using a consuming function or | ||||
|  *   by explicitly calling `sp_char_grid_free`. | ||||
|  */ | ||||
| SPCharGrid *sp_char_grid_clone(const SPCharGrid *char_grid); | ||||
| 
 | ||||
| /**
 | ||||
|  * Sets the value of all cells in the [SPCharGrid]. | ||||
|  * | ||||
|  * # Arguments | ||||
|  * | ||||
|  * - `char_grid`: instance to write to | ||||
|  * - `value`: the value to set all cells to | ||||
|  * | ||||
|  * # Panics | ||||
|  * | ||||
|  * - when `char_grid` is NULL | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - `char_grid` points to a valid [SPCharGrid] | ||||
|  * - `char_grid` is not written to or read from concurrently | ||||
|  */ | ||||
| void sp_char_grid_fill(SPCharGrid *char_grid, uint32_t value); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deallocates a [SPCharGrid]. | ||||
|  * | ||||
|  * # Panics | ||||
|  * | ||||
|  * - when `char_grid` is NULL | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - `char_grid` points to a valid [SPCharGrid] | ||||
|  * - `char_grid` is not used concurrently or after char_grid call | ||||
|  * - `char_grid` was not passed to another consuming function, e.g. to create a [SPCommand] | ||||
|  * | ||||
|  * [SPCommand]: [crate::SPCommand] | ||||
|  */ | ||||
| void sp_char_grid_free(SPCharGrid *char_grid); | ||||
| 
 | ||||
| /**
 | ||||
|  * Gets the current value at the specified position. | ||||
|  * | ||||
|  * # Arguments | ||||
|  * | ||||
|  * - `char_grid`: instance to read from | ||||
|  * - `x` and `y`: position of the cell to read | ||||
|  * | ||||
|  * # Panics | ||||
|  * | ||||
|  * - when `char_grid` is NULL | ||||
|  * - when accessing `x` or `y` out of bounds | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - `char_grid` points to a valid [SPCharGrid] | ||||
|  * - `char_grid` is not written to concurrently | ||||
|  */ | ||||
| uint32_t sp_char_grid_get(const SPCharGrid *char_grid, size_t x, size_t y); | ||||
| 
 | ||||
| /**
 | ||||
|  * Gets the height of the [SPCharGrid] instance. | ||||
|  * | ||||
|  * # Arguments | ||||
|  * | ||||
|  * - `char_grid`: instance to read from | ||||
|  * | ||||
|  * # Panics | ||||
|  * | ||||
|  * - when `char_grid` is NULL | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - `char_grid` points to a valid [SPCharGrid] | ||||
|  */ | ||||
| size_t sp_char_grid_height(const SPCharGrid *char_grid); | ||||
| 
 | ||||
| /**
 | ||||
|  * Loads a [SPCharGrid] with the specified dimensions from the provided data. | ||||
|  * | ||||
|  * Will never return NULL. | ||||
|  * | ||||
|  * # Panics | ||||
|  * | ||||
|  * - when `data` is NULL | ||||
|  * - when the provided `data_length` does not match `height` and `width` | ||||
|  * - when `data` is not valid UTF-8 | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - `data` points to a valid memory location of at least `data_length` | ||||
|  *   bytes in size. | ||||
|  * - the returned instance is freed in some way, either by using a consuming function or | ||||
|  *   by explicitly calling `sp_char_grid_free`. | ||||
|  */ | ||||
| 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. | ||||
|  * | ||||
|  * returns: [SPCharGrid] initialized to 0. Will never return NULL. | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - the returned instance is freed in some way, either by using a consuming function or | ||||
|  *   by explicitly calling `sp_char_grid_free`. | ||||
|  */ | ||||
| SPCharGrid *sp_char_grid_new(size_t width, | ||||
|                              size_t height); | ||||
| 
 | ||||
| /**
 | ||||
|  * Sets the value of the specified position in the [SPCharGrid]. | ||||
|  * | ||||
|  * # Arguments | ||||
|  * | ||||
|  * - `char_grid`: instance to write to | ||||
|  * - `x` and `y`: position of the cell | ||||
|  * - `value`: the value to write to the cell | ||||
|  * | ||||
|  * returns: old value of the cell | ||||
|  * | ||||
|  * # Panics | ||||
|  * | ||||
|  * - when `char_grid` is NULL | ||||
|  * - when accessing `x` or `y` out of bounds | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - `char_grid` points to a valid [SPBitVec] | ||||
|  * - `char_grid` is not written to or read from concurrently | ||||
|  * | ||||
|  * [SPBitVec]: [crate::SPBitVec] | ||||
|  */ | ||||
| void sp_char_grid_set(SPCharGrid *char_grid, | ||||
|                       size_t x, | ||||
|                       size_t y, | ||||
|                       uint32_t value); | ||||
| 
 | ||||
| /**
 | ||||
|  * Gets the width of the [SPCharGrid] instance. | ||||
|  * | ||||
|  * # Arguments | ||||
|  * | ||||
|  * - `char_grid`: instance to read from | ||||
|  * | ||||
|  * # Panics | ||||
|  * | ||||
|  * - when `char_grid` is NULL | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - `char_grid` points to a valid [SPCharGrid] | ||||
|  */ | ||||
| size_t sp_char_grid_width(const SPCharGrid *char_grid); | ||||
| 
 | ||||
| /**
 | ||||
|  * Set pixel data starting at the pixel offset on screen. | ||||
|  * | ||||
|  | @ -1101,7 +1324,7 @@ SPCommand *sp_command_clear(void); | |||
| SPCommand *sp_command_clone(const SPCommand *command); | ||||
| 
 | ||||
| /**
 | ||||
|  * Show text on the screen. | ||||
|  * Show codepage 437 encoded text on the screen. | ||||
|  * | ||||
|  * The passed [SPCp437Grid] gets consumed. | ||||
|  * | ||||
|  | @ -1201,6 +1424,30 @@ SPCommand *sp_command_hard_reset(void); | |||
|  */ | ||||
| SPCommand *sp_command_try_from_packet(SPPacket *packet); | ||||
| 
 | ||||
| /**
 | ||||
|  * Show UTF-8 encoded text on the screen. | ||||
|  * | ||||
|  * The passed [SPCharGrid] gets consumed. | ||||
|  * | ||||
|  * Returns: a new [servicepoint::Command::Utf8Data] instance. Will never return NULL. | ||||
|  * | ||||
|  * # Panics | ||||
|  * | ||||
|  * - when `grid` is null | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - `grid` points to a valid instance of [SPCharGrid] | ||||
|  * - `grid` is not used concurrently or after this call | ||||
|  * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or | ||||
|  *   by explicitly calling `sp_command_free`. | ||||
|  */ | ||||
| SPCommand *sp_command_utf8_data(size_t x, | ||||
|                                 size_t y, | ||||
|                                 SPCharGrid *grid); | ||||
| 
 | ||||
| /**
 | ||||
|  * Creates a new instance of [SPConnection] for testing that does not actually send anything. | ||||
|  * | ||||
|  | @ -1528,7 +1775,7 @@ SPPacket *sp_packet_clone(const SPPacket *packet); | |||
|  * | ||||
|  * # Panics | ||||
|  * | ||||
|  * - when `sp_packet_free` is NULL | ||||
|  * - when `packet` is NULL | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  | @ -1560,6 +1807,40 @@ void sp_packet_free(SPPacket *packet); | |||
|  */ | ||||
| SPPacket *sp_packet_from_command(SPCommand *command); | ||||
| 
 | ||||
| /**
 | ||||
|  * Creates a raw [SPPacket] from parts. | ||||
|  * | ||||
|  * # Arguments | ||||
|  * | ||||
|  * - `command_code` specifies which command this packet contains | ||||
|  * - `a`, `b`, `c` and `d` are command-specific header values | ||||
|  * - `payload` is the optional data that is part of the command | ||||
|  * - `payload_len` is the size of the payload | ||||
|  * | ||||
|  * returns: new instance. Will never return null. | ||||
|  * | ||||
|  * # Panics | ||||
|  * | ||||
|  * - when `payload` is null, but `payload_len` is not zero | ||||
|  * - when `payload_len` is zero, but `payload` is nonnull | ||||
|  * | ||||
|  * # Safety | ||||
|  * | ||||
|  * The caller has to make sure that: | ||||
|  * | ||||
|  * - `payload` points to a valid memory region of at least `payload_len` bytes | ||||
|  * - `payload` is not written to concurrently | ||||
|  * - the returned [SPPacket] instance is freed in some way, either by using a consuming function or | ||||
|  *   by explicitly calling [sp_packet_free]. | ||||
|  */ | ||||
| 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. | ||||
|  * | ||||
|  |  | |||
							
								
								
									
										263
									
								
								crates/servicepoint_binding_c/src/char_grid.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								crates/servicepoint_binding_c/src/char_grid.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,263 @@ | |||
| //! C functions for interacting with [SPCharGrid]s
 | ||||
| //!
 | ||||
| //! prefix `sp_char_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.
 | ||||
| ///
 | ||||
| /// # Safety
 | ||||
| ///
 | ||||
| /// The caller has to make sure that:
 | ||||
| ///
 | ||||
| /// - the returned instance is freed in some way, either by using a consuming function or
 | ||||
| ///   by explicitly calling `sp_char_grid_free`.
 | ||||
| #[no_mangle] | ||||
| pub unsafe extern "C" fn sp_char_grid_new( | ||||
|     width: usize, | ||||
|     height: usize, | ||||
| ) -> NonNull<SPCharGrid> { | ||||
|     let result = | ||||
|         Box::new(SPCharGrid(servicepoint::CharGrid::new(width, height))); | ||||
|     NonNull::from(Box::leak(result)) | ||||
| } | ||||
| 
 | ||||
| /// Loads a [SPCharGrid] with the specified dimensions from the provided data.
 | ||||
| ///
 | ||||
| /// Will never return NULL.
 | ||||
| ///
 | ||||
| /// # Panics
 | ||||
| ///
 | ||||
| /// - when `data` is NULL
 | ||||
| /// - when the provided `data_length` does not match `height` and `width`
 | ||||
| /// - when `data` is not valid UTF-8
 | ||||
| ///
 | ||||
| /// # Safety
 | ||||
| ///
 | ||||
| /// The caller has to make sure that:
 | ||||
| ///
 | ||||
| /// - `data` points to a valid memory location of at least `data_length`
 | ||||
| ///   bytes in size.
 | ||||
| /// - the returned instance is freed in some way, either by using a consuming function or
 | ||||
| ///   by explicitly calling `sp_char_grid_free`.
 | ||||
| #[no_mangle] | ||||
| pub unsafe extern "C" fn sp_char_grid_load( | ||||
|     width: usize, | ||||
|     height: usize, | ||||
|     data: *const u8, | ||||
|     data_length: usize, | ||||
| ) -> NonNull<SPCharGrid> { | ||||
|     assert!(data.is_null()); | ||||
|     let data = 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)) | ||||
| } | ||||
| 
 | ||||
| /// Clones a [SPCharGrid].
 | ||||
| ///
 | ||||
| /// Will never return NULL.
 | ||||
| ///
 | ||||
| /// # Panics
 | ||||
| ///
 | ||||
| /// - when `char_grid` is NULL
 | ||||
| ///
 | ||||
| /// # Safety
 | ||||
| ///
 | ||||
| /// The caller has to make sure that:
 | ||||
| ///
 | ||||
| /// - `char_grid` points to a valid [SPCharGrid]
 | ||||
| /// - `char_grid` is not written to concurrently
 | ||||
| /// - the returned instance is freed in some way, either by using a consuming function or
 | ||||
| ///   by explicitly calling `sp_char_grid_free`.
 | ||||
| #[no_mangle] | ||||
| pub unsafe extern "C" fn sp_char_grid_clone( | ||||
|     char_grid: *const SPCharGrid, | ||||
| ) -> NonNull<SPCharGrid> { | ||||
|     assert!(!char_grid.is_null()); | ||||
|     let result = Box::new((*char_grid).clone()); | ||||
|     NonNull::from(Box::leak(result)) | ||||
| } | ||||
| 
 | ||||
| /// Deallocates a [SPCharGrid].
 | ||||
| ///
 | ||||
| /// # Panics
 | ||||
| ///
 | ||||
| /// - when `char_grid` is NULL
 | ||||
| ///
 | ||||
| /// # Safety
 | ||||
| ///
 | ||||
| /// The caller has to make sure that:
 | ||||
| ///
 | ||||
| /// - `char_grid` points to a valid [SPCharGrid]
 | ||||
| /// - `char_grid` is not used concurrently or after char_grid call
 | ||||
| /// - `char_grid` was not passed to another consuming function, e.g. to create a [SPCommand]
 | ||||
| ///
 | ||||
| /// [SPCommand]: [crate::SPCommand]
 | ||||
| #[no_mangle] | ||||
| pub unsafe extern "C" fn sp_char_grid_free(char_grid: *mut SPCharGrid) { | ||||
|     assert!(!char_grid.is_null()); | ||||
|     _ = Box::from_raw(char_grid); | ||||
| } | ||||
| 
 | ||||
| /// Gets the current value at the specified position.
 | ||||
| ///
 | ||||
| /// # Arguments
 | ||||
| ///
 | ||||
| /// - `char_grid`: instance to read from
 | ||||
| /// - `x` and `y`: position of the cell to read
 | ||||
| ///
 | ||||
| /// # Panics
 | ||||
| ///
 | ||||
| /// - when `char_grid` is NULL
 | ||||
| /// - when accessing `x` or `y` out of bounds
 | ||||
| ///
 | ||||
| /// # Safety
 | ||||
| ///
 | ||||
| /// The caller has to make sure that:
 | ||||
| ///
 | ||||
| /// - `char_grid` points to a valid [SPCharGrid]
 | ||||
| /// - `char_grid` is not written to concurrently
 | ||||
| #[no_mangle] | ||||
| pub unsafe extern "C" fn sp_char_grid_get( | ||||
|     char_grid: *const SPCharGrid, | ||||
|     x: usize, | ||||
|     y: usize, | ||||
| ) -> u32 { | ||||
|     assert!(!char_grid.is_null()); | ||||
|     (*char_grid).0.get(x, y) as u32 | ||||
| } | ||||
| 
 | ||||
| /// Sets the value of the specified position in the [SPCharGrid].
 | ||||
| ///
 | ||||
| /// # Arguments
 | ||||
| ///
 | ||||
| /// - `char_grid`: instance to write to
 | ||||
| /// - `x` and `y`: position of the cell
 | ||||
| /// - `value`: the value to write to the cell
 | ||||
| ///
 | ||||
| /// returns: old value of the cell
 | ||||
| ///
 | ||||
| /// # Panics
 | ||||
| ///
 | ||||
| /// - when `char_grid` is NULL
 | ||||
| /// - when accessing `x` or `y` out of bounds
 | ||||
| ///
 | ||||
| /// # Safety
 | ||||
| ///
 | ||||
| /// The caller has to make sure that:
 | ||||
| ///
 | ||||
| /// - `char_grid` points to a valid [SPBitVec]
 | ||||
| /// - `char_grid` is not written to or read from concurrently
 | ||||
| ///
 | ||||
| /// [SPBitVec]: [crate::SPBitVec]
 | ||||
| #[no_mangle] | ||||
| pub unsafe extern "C" fn sp_char_grid_set( | ||||
|     char_grid: *mut SPCharGrid, | ||||
|     x: usize, | ||||
|     y: usize, | ||||
|     value: u32, | ||||
| ) { | ||||
|     assert!(!char_grid.is_null()); | ||||
|     (*char_grid).0.set(x, y, char::from_u32(value).unwrap()); | ||||
| } | ||||
| 
 | ||||
| /// Sets the value of all cells in the [SPCharGrid].
 | ||||
| ///
 | ||||
| /// # Arguments
 | ||||
| ///
 | ||||
| /// - `char_grid`: instance to write to
 | ||||
| /// - `value`: the value to set all cells to
 | ||||
| ///
 | ||||
| /// # Panics
 | ||||
| ///
 | ||||
| /// - when `char_grid` is NULL
 | ||||
| ///
 | ||||
| /// # Safety
 | ||||
| ///
 | ||||
| /// The caller has to make sure that:
 | ||||
| ///
 | ||||
| /// - `char_grid` points to a valid [SPCharGrid]
 | ||||
| /// - `char_grid` is not written to or read from concurrently
 | ||||
| #[no_mangle] | ||||
| pub unsafe extern "C" fn sp_char_grid_fill( | ||||
|     char_grid: *mut SPCharGrid, | ||||
|     value: u32, | ||||
| ) { | ||||
|     assert!(!char_grid.is_null()); | ||||
|     (*char_grid).0.fill(char::from_u32(value).unwrap()); | ||||
| } | ||||
| 
 | ||||
| /// Gets the width of the [SPCharGrid] instance.
 | ||||
| ///
 | ||||
| /// # Arguments
 | ||||
| ///
 | ||||
| /// - `char_grid`: instance to read from
 | ||||
| ///
 | ||||
| /// # Panics
 | ||||
| ///
 | ||||
| /// - when `char_grid` is NULL
 | ||||
| ///
 | ||||
| /// # Safety
 | ||||
| ///
 | ||||
| /// The caller has to make sure that:
 | ||||
| ///
 | ||||
| /// - `char_grid` points to a valid [SPCharGrid]
 | ||||
| #[no_mangle] | ||||
| pub unsafe extern "C" fn sp_char_grid_width( | ||||
|     char_grid: *const SPCharGrid, | ||||
| ) -> usize { | ||||
|     assert!(!char_grid.is_null()); | ||||
|     (*char_grid).0.width() | ||||
| } | ||||
| 
 | ||||
| /// Gets the height of the [SPCharGrid] instance.
 | ||||
| ///
 | ||||
| /// # Arguments
 | ||||
| ///
 | ||||
| /// - `char_grid`: instance to read from
 | ||||
| ///
 | ||||
| /// # Panics
 | ||||
| ///
 | ||||
| /// - when `char_grid` is NULL
 | ||||
| ///
 | ||||
| /// # Safety
 | ||||
| ///
 | ||||
| /// The caller has to make sure that:
 | ||||
| ///
 | ||||
| /// - `char_grid` points to a valid [SPCharGrid]
 | ||||
| #[no_mangle] | ||||
| pub unsafe extern "C" fn sp_char_grid_height( | ||||
|     char_grid: *const SPCharGrid, | ||||
| ) -> usize { | ||||
|     assert!(!char_grid.is_null()); | ||||
|     (*char_grid).0.height() | ||||
| } | ||||
|  | @ -5,8 +5,8 @@ | |||
| use std::ptr::{null_mut, NonNull}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     SPBitVec, SPBitmap, SPBrightnessGrid, SPCompressionCode, SPCp437Grid, | ||||
|     SPPacket, | ||||
|     SPBitVec, SPBitmap, SPBrightnessGrid, SPCharGrid, SPCompressionCode, | ||||
|     SPCp437Grid, SPPacket, | ||||
| }; | ||||
| 
 | ||||
| /// A low-level display command.
 | ||||
|  | @ -366,7 +366,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_xor( | |||
|     NonNull::from(Box::leak(result)) | ||||
| } | ||||
| 
 | ||||
| /// Show text on the screen.
 | ||||
| /// Show codepage 437 encoded text on the screen.
 | ||||
| ///
 | ||||
| /// The passed [SPCp437Grid] gets consumed.
 | ||||
| ///
 | ||||
|  | @ -399,6 +399,39 @@ pub unsafe extern "C" fn sp_command_cp437_data( | |||
|     NonNull::from(Box::leak(result)) | ||||
| } | ||||
| 
 | ||||
| /// Show UTF-8 encoded text on the screen.
 | ||||
| ///
 | ||||
| /// The passed [SPCharGrid] gets consumed.
 | ||||
| ///
 | ||||
| /// Returns: a new [servicepoint::Command::Utf8Data] instance. Will never return NULL.
 | ||||
| ///
 | ||||
| /// # Panics
 | ||||
| ///
 | ||||
| /// - when `grid` is null
 | ||||
| ///
 | ||||
| /// # Safety
 | ||||
| ///
 | ||||
| /// The caller has to make sure that:
 | ||||
| ///
 | ||||
| /// - `grid` points to a valid instance of [SPCharGrid]
 | ||||
| /// - `grid` is not used concurrently or after this call
 | ||||
| /// - 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_utf8_data( | ||||
|     x: usize, | ||||
|     y: usize, | ||||
|     grid: *mut SPCharGrid, | ||||
| ) -> NonNull<SPCommand> { | ||||
|     assert!(!grid.is_null()); | ||||
|     let grid = *Box::from_raw(grid); | ||||
|     let result = Box::new(SPCommand(servicepoint::Command::Utf8Data( | ||||
|         servicepoint::Origin::new(x, y), | ||||
|         grid.0, | ||||
|     ))); | ||||
|     NonNull::from(Box::leak(result)) | ||||
| } | ||||
| 
 | ||||
| /// Sets a window of pixels to the specified values.
 | ||||
| ///
 | ||||
| /// The passed [SPBitmap] gets consumed.
 | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ pub use crate::bitmap::*; | |||
| pub use crate::bitvec::*; | ||||
| pub use crate::brightness_grid::*; | ||||
| pub use crate::byte_slice::*; | ||||
| pub use crate::char_grid::*; | ||||
| pub use crate::command::*; | ||||
| pub use crate::connection::*; | ||||
| pub use crate::constants::*; | ||||
|  | @ -39,6 +40,7 @@ mod bitmap; | |||
| mod bitvec; | ||||
| mod brightness_grid; | ||||
| mod byte_slice; | ||||
| mod char_grid; | ||||
| mod command; | ||||
| mod connection; | ||||
| mod constants; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vinzenz Schroeter
						Vinzenz Schroeter