diff --git a/Cargo.lock b/Cargo.lock index 45d9e17..5bc28b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -147,9 +147,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.29" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e804ac3194a48bb129643eb1d62fcc20d18c6b8c181704489353d13120bcd1" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "jobserver", "libc", @@ -610,7 +610,7 @@ dependencies = [ [[package]] name = "servicepoint" -version = "0.9.1" +version = "0.10.0" dependencies = [ "bitvec", "bzip2", @@ -626,7 +626,7 @@ dependencies = [ [[package]] name = "servicepoint_binding_c" -version = "0.9.1" +version = "0.10.0" dependencies = [ "cbindgen", "servicepoint", @@ -634,7 +634,7 @@ dependencies = [ [[package]] name = "servicepoint_binding_cs" -version = "0.9.1" +version = "0.10.0" dependencies = [ "csbindgen", "servicepoint", diff --git a/Cargo.toml b/Cargo.toml index 8a6f9c9..6e534de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ ] [workspace.package] -version = "0.9.1" +version = "0.10.0" [workspace.lints.rust] missing-docs = "warn" diff --git a/crates/servicepoint/README.md b/crates/servicepoint/README.md index c7139da..303d29d 100644 --- a/crates/servicepoint/README.md +++ b/crates/servicepoint/README.md @@ -17,7 +17,7 @@ cargo add servicepoint or ```toml [dependencies] -servicepoint = "0.9.1" +servicepoint = "0.10.0" ``` ## Examples diff --git a/crates/servicepoint/examples/announce.rs b/crates/servicepoint/examples/announce.rs index ff95479..af78a54 100644 --- a/crates/servicepoint/examples/announce.rs +++ b/crates/servicepoint/examples/announce.rs @@ -6,16 +6,26 @@ use servicepoint::{CharGrid, Command, Connection, Cp437Grid, Origin}; #[derive(Parser, Debug)] struct Cli { - #[arg(short, long, default_value = "localhost:2342")] + #[arg( + short, + long, + default_value = "localhost:2342", + help = "Address of the display" + )] destination: String, - #[arg(short, long, num_args = 1.., value_delimiter = '\n')] + #[arg(short, long, num_args = 1.., value_delimiter = '\n', + help = "Text to send - specify multiple times for multiple lines")] text: Vec, - #[arg(short, long, default_value_t = true)] + #[arg( + short, + long, + default_value_t = true, + help = "Clear screen before sending text" + )] clear: bool, } -/// example: `cargo run -- --text "Hallo, -/// CCCB"` +/// example: `cargo run -- --text "Hallo" --text "CCCB"` fn main() { let mut cli = Cli::parse(); if cli.text.is_empty() { @@ -31,15 +41,11 @@ fn main() { .expect("sending clear failed"); } - let text = cli.text.iter().fold(String::new(), move |str, line| { - let is_first = str.is_empty(); - str + if is_first { "" } else { "\n" } + line - }); - + let text = cli.text.join("\n"); let grid = CharGrid::from(&*text); let cp437_grid = Cp437Grid::from(&grid); connection - .send(Command::Cp437Data(Origin::new(0, 0), cp437_grid)) + .send(Command::Cp437Data(Origin::ZERO, cp437_grid)) .expect("sending text failed"); } diff --git a/crates/servicepoint/examples/brightness_tester.rs b/crates/servicepoint/examples/brightness_tester.rs index 5f2bd90..8a31ee8 100644 --- a/crates/servicepoint/examples/brightness_tester.rs +++ b/crates/servicepoint/examples/brightness_tester.rs @@ -15,23 +15,24 @@ fn main() { let connection = Connection::open(cli.destination) .expect("could not connect to display"); - let mut pixels = PixelGrid::max_sized(); + let mut pixels = Bitmap::max_sized(); pixels.fill(true); let command = Command::BitmapLinearWin( - Origin::new(0, 0), + Origin::ZERO, pixels, CompressionCode::Uncompressed, ); connection.send(command).expect("send failed"); - let max_brightness = usize::from(u8::from(Brightness::MAX)); + let max_brightness: u8 = Brightness::MAX.into(); let mut brightnesses = BrightnessGrid::new(TILE_WIDTH, TILE_HEIGHT); for (index, byte) in brightnesses.data_ref_mut().iter_mut().enumerate() { - *byte = Brightness::try_from((index % max_brightness) as u8).unwrap(); + let level = index as u8 % max_brightness; + *byte = Brightness::try_from(level).unwrap(); } connection - .send(Command::CharBrightness(Origin::new(0, 0), brightnesses)) + .send(Command::CharBrightness(Origin::ZERO, brightnesses)) .expect("send failed"); } diff --git a/crates/servicepoint/examples/game_of_life.rs b/crates/servicepoint/examples/game_of_life.rs index 29507ce..76e8c70 100644 --- a/crates/servicepoint/examples/game_of_life.rs +++ b/crates/servicepoint/examples/game_of_life.rs @@ -24,7 +24,7 @@ fn main() { loop { let command = Command::BitmapLinearWin( - Origin::new(0, 0), + Origin::ZERO, field.clone(), CompressionCode::Lzma, ); @@ -34,7 +34,7 @@ fn main() { } } -fn iteration(field: PixelGrid) -> PixelGrid { +fn iteration(field: Bitmap) -> Bitmap { let mut next = field.clone(); for x in 0..field.width() { for y in 0..field.height() { @@ -51,7 +51,7 @@ fn iteration(field: PixelGrid) -> PixelGrid { next } -fn count_neighbors(field: &PixelGrid, x: i32, y: i32) -> i32 { +fn count_neighbors(field: &Bitmap, x: i32, y: i32) -> i32 { let mut count = 0; for nx in x - 1..=x + 1 { for ny in y - 1..=y + 1 { @@ -78,8 +78,8 @@ fn count_neighbors(field: &PixelGrid, x: i32, y: i32) -> i32 { count } -fn make_random_field(probability: f64) -> PixelGrid { - let mut field = PixelGrid::max_sized(); +fn make_random_field(probability: f64) -> Bitmap { + let mut field = Bitmap::max_sized(); let mut rng = rand::thread_rng(); let d = distributions::Bernoulli::new(probability).unwrap(); for x in 0..field.width() { diff --git a/crates/servicepoint/examples/moving_line.rs b/crates/servicepoint/examples/moving_line.rs index 5682be4..50cfcca 100644 --- a/crates/servicepoint/examples/moving_line.rs +++ b/crates/servicepoint/examples/moving_line.rs @@ -16,7 +16,7 @@ fn main() { let connection = Connection::open(Cli::parse().destination) .expect("could not connect to display"); - let mut pixels = PixelGrid::max_sized(); + let mut pixels = Bitmap::max_sized(); for x_offset in 0..usize::MAX { pixels.fill(false); @@ -25,7 +25,7 @@ fn main() { } let command = Command::BitmapLinearWin( - Origin::new(0, 0), + Origin::ZERO, pixels.clone(), CompressionCode::Lzma, ); diff --git a/crates/servicepoint/examples/random_brightness.rs b/crates/servicepoint/examples/random_brightness.rs index 01487a2..f47cf72 100644 --- a/crates/servicepoint/examples/random_brightness.rs +++ b/crates/servicepoint/examples/random_brightness.rs @@ -28,11 +28,11 @@ fn main() { // put all pixels in on state if cli.enable_all { - let mut filled_grid = PixelGrid::max_sized(); + let mut filled_grid = Bitmap::max_sized(); filled_grid.fill(true); let command = BitmapLinearWin( - Origin::new(0, 0), + Origin::ZERO, filled_grid, CompressionCode::Lzma, ); diff --git a/crates/servicepoint/examples/websocket.rs b/crates/servicepoint/examples/websocket.rs index 71be6a3..a0c43c0 100644 --- a/crates/servicepoint/examples/websocket.rs +++ b/crates/servicepoint/examples/websocket.rs @@ -1,7 +1,7 @@ //! Example for how to use the WebSocket connection use servicepoint::{ - Command, CompressionCode, Connection, Grid, Origin, PixelGrid, + Bitmap, Command, CompressionCode, Connection, Grid, Origin, }; fn main() { @@ -13,7 +13,7 @@ fn main() { // use send_mut instead of send connection.send_mut(Command::Clear).unwrap(); - let mut pixels = PixelGrid::max_sized(); + let mut pixels = Bitmap::max_sized(); pixels.fill(true); // use send_mut instead of send diff --git a/crates/servicepoint/examples/wiping_clear.rs b/crates/servicepoint/examples/wiping_clear.rs index 03e8215..a3bf04a 100644 --- a/crates/servicepoint/examples/wiping_clear.rs +++ b/crates/servicepoint/examples/wiping_clear.rs @@ -25,7 +25,7 @@ fn main() { let connection = Connection::open(cli.destination) .expect("could not connect to display"); - let mut enabled_pixels = PixelGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT); + let mut enabled_pixels = Bitmap::max_sized(); enabled_pixels.fill(true); for x_offset in 0..PIXEL_WIDTH { diff --git a/crates/servicepoint/src/pixel_grid.rs b/crates/servicepoint/src/bitmap.rs similarity index 74% rename from crates/servicepoint/src/pixel_grid.rs rename to crates/servicepoint/src/bitmap.rs index 746f2ac..657e155 100644 --- a/crates/servicepoint/src/pixel_grid.rs +++ b/crates/servicepoint/src/bitmap.rs @@ -6,21 +6,21 @@ use crate::{BitVec, DataRef, Grid, SpBitVec, PIXEL_HEIGHT, PIXEL_WIDTH}; /// A grid of pixels stored in packed bytes. #[derive(Debug, Clone, PartialEq)] -pub struct PixelGrid { +pub struct Bitmap { width: usize, height: usize, bit_vec: SpBitVec, } -impl PixelGrid { - /// Creates a new [PixelGrid] with the specified dimensions. +impl Bitmap { + /// Creates a new [Bitmap] with the specified dimensions. /// /// # Arguments /// /// - `width`: size in pixels in x-direction /// - `height`: size in pixels in y-direction /// - /// returns: [PixelGrid] initialized to all pixels off + /// returns: [Bitmap] initialized to all pixels off /// /// # Panics /// @@ -40,14 +40,14 @@ impl PixelGrid { Self::new(PIXEL_WIDTH, PIXEL_HEIGHT) } - /// Loads a [PixelGrid] with the specified dimensions from the provided data. + /// Loads a [Bitmap] with the specified dimensions from the provided data. /// /// # Arguments /// /// - `width`: size in pixels in x-direction /// - `height`: size in pixels in y-direction /// - /// returns: [PixelGrid] that contains a copy of the provided data + /// returns: [Bitmap] that contains a copy of the provided data /// /// # Panics /// @@ -64,12 +64,12 @@ impl PixelGrid { } } - /// Iterate over all cells in [PixelGrid]. + /// Iterate over all cells in [Bitmap]. /// /// Order is equivalent to the following loop: /// ``` - /// # use servicepoint::{PixelGrid, Grid}; - /// # let grid = PixelGrid::new(8,2); + /// # use servicepoint::{Bitmap, Grid}; + /// # let grid = Bitmap::new(8,2); /// for y in 0..grid.height() { /// for x in 0..grid.width() { /// grid.get(x, y); @@ -80,12 +80,12 @@ impl PixelGrid { self.bit_vec.iter().by_refs() } - /// Iterate over all cells in [PixelGrid] mutably. + /// Iterate over all cells in [Bitmap] mutably. /// /// Order is equivalent to the following loop: /// ``` - /// # use servicepoint::{PixelGrid, Grid}; - /// # let mut grid = PixelGrid::new(8,2); + /// # use servicepoint::{Bitmap, Grid}; + /// # let mut grid = Bitmap::new(8,2); /// # let value = false; /// for y in 0..grid.height() { /// for x in 0..grid.width() { @@ -96,8 +96,8 @@ impl PixelGrid { /// /// # Example /// ``` - /// # use servicepoint::{PixelGrid, Grid}; - /// # let mut grid = PixelGrid::new(8,2); + /// # use servicepoint::{Bitmap, Grid}; + /// # let mut grid = Bitmap::new(8,2); /// # let value = false; /// for (index, mut pixel) in grid.iter_mut().enumerate() { /// pixel.set(index % 2 == 0) @@ -107,17 +107,17 @@ impl PixelGrid { self.bit_vec.iter_mut() } - /// Iterate over all rows in [PixelGrid] top to bottom. + /// Iterate over all rows in [Bitmap] top to bottom. pub fn iter_rows(&self) -> IterRows { IterRows { - pixel_grid: self, + bitmap: self, row: 0, } } } -impl Grid for PixelGrid { - /// Sets the value of the specified position in the [PixelGrid]. +impl Grid for Bitmap { + /// Sets the value of the specified position in the [Bitmap]. /// /// # Arguments /// @@ -139,7 +139,7 @@ impl Grid for PixelGrid { self.bit_vec[x + y * self.width] } - /// Sets the state of all pixels in the [PixelGrid]. + /// Sets the state of all pixels in the [Bitmap]. /// /// # Arguments /// @@ -158,7 +158,7 @@ impl Grid for PixelGrid { } } -impl DataRef for PixelGrid { +impl DataRef for Bitmap { fn data_ref_mut(&mut self) -> &mut [u8] { self.bit_vec.as_raw_mut_slice() } @@ -168,15 +168,15 @@ impl DataRef for PixelGrid { } } -impl From for Vec { - /// Turns a [PixelGrid] into the underlying [`Vec`]. - fn from(value: PixelGrid) -> Self { +impl From for Vec { + /// Turns a [Bitmap] into the underlying [`Vec`]. + fn from(value: Bitmap) -> Self { value.bit_vec.into() } } pub struct IterRows<'t> { - pixel_grid: &'t PixelGrid, + bitmap: &'t Bitmap, row: usize, } @@ -184,24 +184,24 @@ impl<'t> Iterator for IterRows<'t> { type Item = &'t BitSlice; fn next(&mut self) -> Option { - if self.row >= self.pixel_grid.height { + if self.row >= self.bitmap.height { return None; } - let start = self.row * self.pixel_grid.width; - let end = start + self.pixel_grid.width; + let start = self.row * self.bitmap.width; + let end = start + self.bitmap.width; self.row += 1; - Some(&self.pixel_grid.bit_vec[start..end]) + Some(&self.bitmap.bit_vec[start..end]) } } #[cfg(test)] mod tests { - use crate::{DataRef, Grid, PixelGrid}; + use crate::{Bitmap, DataRef, Grid}; #[test] fn fill() { - let mut grid = PixelGrid::new(8, 2); + let mut grid = Bitmap::new(8, 2); assert_eq!(grid.data_ref(), [0x00, 0x00]); grid.fill(true); @@ -213,7 +213,7 @@ mod tests { #[test] fn get_set() { - let mut grid = PixelGrid::new(8, 2); + let mut grid = Bitmap::new(8, 2); assert!(!grid.get(0, 0)); assert!(!grid.get(1, 1)); @@ -228,7 +228,7 @@ mod tests { #[test] fn load() { - let mut grid = PixelGrid::new(8, 3); + let mut grid = Bitmap::new(8, 3); for x in 0..grid.width { for y in 0..grid.height { grid.set(x, y, (x + y) % 2 == 0); @@ -239,33 +239,33 @@ mod tests { let data: Vec = grid.into(); - let grid = PixelGrid::load(8, 3, &data); + let grid = Bitmap::load(8, 3, &data); assert_eq!(grid.data_ref(), [0xAA, 0x55, 0xAA]); } #[test] #[should_panic] fn out_of_bounds_x() { - let vec = PixelGrid::new(8, 2); + let vec = Bitmap::new(8, 2); vec.get(8, 1); } #[test] #[should_panic] fn out_of_bounds_y() { - let mut vec = PixelGrid::new(8, 2); + let mut vec = Bitmap::new(8, 2); vec.set(1, 2, false); } #[test] fn iter() { - let grid = PixelGrid::new(8, 2); + let grid = Bitmap::new(8, 2); assert_eq!(16, grid.iter().count()) } #[test] fn iter_rows() { - let grid = PixelGrid::load(8, 2, &[0x04, 0x40]); + let grid = Bitmap::load(8, 2, &[0x04, 0x40]); let mut iter = grid.iter_rows(); assert_eq!(iter.next().unwrap().count_ones(), 1); @@ -275,7 +275,7 @@ mod tests { #[test] fn iter_mut() { - let mut grid = PixelGrid::new(8, 2); + let mut grid = Bitmap::new(8, 2); for (index, mut pixel) in grid.iter_mut().enumerate() { pixel.set(index % 2 == 0); } @@ -284,7 +284,7 @@ mod tests { #[test] fn data_ref_mut() { - let mut grid = PixelGrid::new(8, 2); + let mut grid = Bitmap::new(8, 2); let data = grid.data_ref_mut(); data[1] = 0x0F; assert!(grid.get(7, 1)); diff --git a/crates/servicepoint/src/brightness.rs b/crates/servicepoint/src/brightness.rs index ad07aa6..e5a82b3 100644 --- a/crates/servicepoint/src/brightness.rs +++ b/crates/servicepoint/src/brightness.rs @@ -60,6 +60,17 @@ impl Brightness { pub const MAX: Brightness = Brightness(11); /// lowest possible brightness value, 0 pub const MIN: Brightness = Brightness(0); + + /// Create a brightness value without returning an error for brightnesses above [Brightness::MAX]. + /// + /// returns: the specified value as a [Brightness], or [Brightness::MAX]. + pub fn saturating_from(value: u8) -> Brightness { + if value > Brightness::MAX.into() { + Brightness::MAX + } else { + Brightness(value) + } + } } impl Default for Brightness { @@ -138,4 +149,10 @@ mod tests { let actual = PrimitiveGrid::from(&grid); assert_eq!(actual.data_ref(), &[11, 0, 11, 11]); } + + #[test] + fn saturating_convert() { + assert_eq!(Brightness::MAX, Brightness::saturating_from(100)); + assert_eq!(Brightness(5), Brightness::saturating_from(5)); + } } diff --git a/crates/servicepoint/src/command.rs b/crates/servicepoint/src/command.rs index abe983c..eead79d 100644 --- a/crates/servicepoint/src/command.rs +++ b/crates/servicepoint/src/command.rs @@ -4,7 +4,7 @@ use crate::{ command_code::CommandCode, compression::into_decompressed, packet::{Header, Packet}, - Brightness, BrightnessGrid, CompressionCode, Cp437Grid, Origin, PixelGrid, + Bitmap, Brightness, BrightnessGrid, CompressionCode, Cp437Grid, Origin, Pixels, PrimitiveGrid, SpBitVec, Tiles, TILE_SIZE, }; @@ -76,12 +76,7 @@ pub enum Command { /// Show text on the screen. /// - /// The text is sent in the form of a 2D grid of characters. - /// - ///
- /// The library does not currently convert between UTF-8 and CP-437. - /// Because Rust expects UTF-8 strings, it might be necessary to only send ASCII for now. - ///
+ /// The text is sent in the form of a 2D grid of [CP-437] encoded characters. /// /// # Examples /// @@ -100,6 +95,7 @@ pub enum Command { /// let grid = Cp437Grid::load_ascii("Hello\nWorld", 5, false).unwrap(); /// connection.send(Command::Cp437Data(Origin::new(2, 2), grid)).unwrap(); /// ``` + /// [CP-437]: https://en.wikipedia.org/wiki/Code_page_437 Cp437Data(Origin, Cp437Grid), /// Overwrites a rectangular region of pixels. @@ -109,23 +105,23 @@ pub enum Command { /// # Examples /// /// ```rust - /// # use servicepoint::{Command, CompressionCode, Grid, PixelGrid}; + /// # use servicepoint::{Command, CompressionCode, Grid, Bitmap}; /// # let connection = servicepoint::Connection::Fake; /// # - /// let mut pixels = PixelGrid::max_sized(); + /// let mut pixels = Bitmap::max_sized(); /// // draw something to the pixels here /// # pixels.set(2, 5, true); /// /// // create command to send pixels /// let command = Command::BitmapLinearWin( - /// servicepoint::Origin::new(0, 0), + /// servicepoint::Origin::ZERO, /// pixels, /// CompressionCode::Uncompressed /// ); /// /// connection.send(command).expect("send failed"); /// ``` - BitmapLinearWin(Origin, PixelGrid, CompressionCode), + BitmapLinearWin(Origin, Bitmap, CompressionCode), /// Set the brightness of all tiles to the same value. /// @@ -217,9 +213,8 @@ pub enum Command { BitmapLegacy, } -#[derive(Debug)] /// Err values for [Command::try_from]. -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub enum TryFromPacketError { /// the contained command code does not correspond to a known command InvalidCommand(u16), @@ -342,7 +337,7 @@ impl Command { Ok(Command::BitmapLinearWin( Origin::new(tiles_x as usize * TILE_SIZE, pixels_y as usize), - PixelGrid::load( + Bitmap::load( tile_w as usize * TILE_SIZE, pixel_h as usize, &payload, @@ -376,7 +371,7 @@ impl Command { } } - /// Helper method for Packets into `BitMapLinear*`-Commands + /// Helper method for Packets into `BitmapLinear*`-Commands fn packet_into_linear_bitmap( packet: Packet, ) -> Result<(SpBitVec, CompressionCode), TryFromPacketError> { @@ -500,7 +495,8 @@ mod tests { command_code::CommandCode, origin::Pixels, packet::{Header, Packet}, - Brightness, Command, CompressionCode, Origin, PixelGrid, PrimitiveGrid, + Bitmap, Brightness, BrightnessGrid, Command, CompressionCode, Origin, + PrimitiveGrid, }; fn round_trip(original: Command) { @@ -592,8 +588,8 @@ mod tests { compression, )); round_trip(Command::BitmapLinearWin( - Origin::new(0, 0), - PixelGrid::max_sized(), + Origin::ZERO, + Bitmap::max_sized(), compression, )); } @@ -718,7 +714,7 @@ mod tests { for compression in all_compressions().to_owned() { let p: Packet = Command::BitmapLinearWin( Origin::new(16, 8), - PixelGrid::new(8, 8), + Bitmap::new(8, 8), compression, ) .into(); @@ -907,4 +903,28 @@ mod tests { Origin::new(1, 0) + Origin::new(3, 2) ); } + + #[test] + fn packet_into_char_brightness_invalid() { + let grid = BrightnessGrid::new(2, 2); + let command = Command::CharBrightness(Origin::ZERO, grid); + let mut packet: Packet = command.into(); + let slot = packet.payload.get_mut(1).unwrap(); + *slot = 23; + assert_eq!( + Command::try_from(packet), + Err(TryFromPacketError::InvalidBrightness(23)) + ); + } + + #[test] + fn packet_into_brightness_invalid() { + let mut packet: Packet = Command::Brightness(Brightness::MAX).into(); + let slot = packet.payload.get_mut(0).unwrap(); + *slot = 42; + assert_eq!( + Command::try_from(packet), + Err(TryFromPacketError::InvalidBrightness(42)) + ); + } } diff --git a/crates/servicepoint/src/compression_code.rs b/crates/servicepoint/src/compression_code.rs index 0440c4e..d7db7cd 100644 --- a/crates/servicepoint/src/compression_code.rs +++ b/crates/servicepoint/src/compression_code.rs @@ -3,14 +3,14 @@ /// # Examples /// /// ```rust -/// # use servicepoint::{Command, CompressionCode, Origin, PixelGrid}; +/// # use servicepoint::{Command, CompressionCode, Origin, Bitmap}; /// // create command without payload compression -/// # let pixels = PixelGrid::max_sized(); -/// _ = Command::BitmapLinearWin(Origin::new(0, 0), pixels, CompressionCode::Uncompressed); +/// # let pixels = Bitmap::max_sized(); +/// _ = Command::BitmapLinearWin(Origin::ZERO, pixels, CompressionCode::Uncompressed); /// /// // create command with payload compressed with lzma and appropriate header flags -/// # let pixels = PixelGrid::max_sized(); -/// _ = Command::BitmapLinearWin(Origin::new(0, 0), pixels, CompressionCode::Lzma); +/// # let pixels = Bitmap::max_sized(); +/// _ = Command::BitmapLinearWin(Origin::ZERO, pixels, CompressionCode::Lzma); /// ``` #[repr(u16)] #[derive(Debug, Clone, Copy, PartialEq)] diff --git a/crates/servicepoint/src/cp437.rs b/crates/servicepoint/src/cp437.rs index dc40627..f757594 100644 --- a/crates/servicepoint/src/cp437.rs +++ b/crates/servicepoint/src/cp437.rs @@ -1,4 +1,7 @@ -use crate::cp437::Cp437LoadError::InvalidChar; +//! Conversion between UTF-8 and CP-437. +//! +//! Most of the functionality is only available with feature "cp437" enabled. + use crate::{Grid, PrimitiveGrid}; use std::collections::HashMap; @@ -10,9 +13,16 @@ pub type Cp437Grid = PrimitiveGrid; /// A grid containing UTF-8 characters. pub type CharGrid = PrimitiveGrid; -#[derive(Debug)] +/// Errors that can occur when loading CP-437. +#[derive(Debug, PartialEq)] pub enum Cp437LoadError { - InvalidChar { index: usize, char: char }, + /// Invalid character in input prevented loading + InvalidChar { + /// invalid character is at this position in input + index: usize, + /// the invalid character + char: char, + }, } impl Cp437Grid { @@ -36,7 +46,7 @@ impl Cp437Grid { for (index, char) in value.chars().enumerate() { if !char.is_ascii() { - return Err(InvalidChar { index, char }); + return Err(Cp437LoadError::InvalidChar { index, char }); } let is_lf = char == '\n'; @@ -85,21 +95,15 @@ mod feature_cp437 { /// An array of 256 elements, mapping most of the CP437 values to UTF-8 characters /// - /// Mostly follows CP437, except for: - /// * 0x0A & 0x0D are kept for use as line endings. - /// * 0x1A is used for SAUCE. - /// * 0x1B is used for ANSI escape sequences. - /// - /// These exclusions should be fine since most programs can't even use them - /// without issues. And this makes rendering simpler too. + /// Mostly follows CP437, except 0x0A, which is kept for use as line ending. /// /// See /// - /// Copied from https://github.com/kip93/cp437-tools. License: GPL-3.0 + /// Mostly copied from https://github.com/kip93/cp437-tools. License: GPL-3.0 #[rustfmt::skip] - const CP437_TO_UTF8: [char; 256] = [ - /* 0X */ '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '\n', '♂', '♀', '\r', '♫', '☼', - /* 1X */ '►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '', '', '∟', '↔', '▲', '▼', + pub const CP437_TO_UTF8: [char; 256] = [ + /* 0X */ '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '\n', '♂', '♀', '♪', '♫', '☼', + /* 1X */ '►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '→', '←', '∟', '↔', '▲', '▼', /* 2X */ ' ', '!', '"', '#', '$', '%', '&', '\'','(', ')', '*', '+', ',', '-', '.', '/', /* 3X */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', /* 4X */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', @@ -116,7 +120,7 @@ mod feature_cp437 { /* FX */ '≡', '±', '≥', '≤', '⌠', '⌡', '÷', '≈', '°', '∙', '·', '√', 'ⁿ', '²', '■', ' ', ]; - const UTF8_TO_CP437: once_cell::sync::Lazy> = + static UTF8_TO_CP437: once_cell::sync::Lazy> = once_cell::sync::Lazy::new(|| { let pairs = CP437_TO_UTF8 .iter() @@ -125,48 +129,34 @@ mod feature_cp437 { HashMap::from_iter(pairs) }); - const MISSING_CHAR_CP437: u8 = 0x3F; + const MISSING_CHAR_CP437: u8 = 0x3F; // '?' impl From<&Cp437Grid> for CharGrid { fn from(value: &Cp437Grid) -> Self { - let mut grid = Self::new(value.width(), value.height()); - - for y in 0..grid.height() { - for x in 0..grid.width() { - let converted = CP437_TO_UTF8[value.get(x, y) as usize]; - grid.set(x, y, converted); - } - } - - grid + value.map(cp437_to_char) } } impl From<&CharGrid> for Cp437Grid { fn from(value: &CharGrid) -> Self { - let mut grid = Self::new(value.width(), value.height()); - - for y in 0..grid.height() { - for x in 0..grid.width() { - let char = value.get(x, y); - let converted = *UTF8_TO_CP437 - .get(&char) - .unwrap_or(&MISSING_CHAR_CP437); - grid.set(x, y, converted); - } - } - - grid + value.map(char_to_cp437) } } impl From<&str> for CharGrid { fn from(value: &str) -> Self { let value = value.replace("\r\n", "\n"); - let lines = value.split('\n').collect::>(); + let mut lines = value + .split('\n') + .map(move |line| line.trim_end()) + .collect::>(); let width = lines.iter().fold(0, move |a, x| std::cmp::max(a, x.len())); + while lines.last().is_some_and(move |line| line.is_empty()) { + _ = lines.pop(); + } + let mut grid = Self::new(width, lines.len()); for (y, line) in lines.iter().enumerate() { for (x, char) in line.chars().enumerate() { @@ -177,6 +167,44 @@ mod feature_cp437 { grid } } + + impl From<&CharGrid> for String { + fn from(value: &CharGrid) -> Self { + value + .iter_rows() + .map(move |chars| { + chars + .collect::() + .replace('\0', " ") + .trim_end() + .to_string() + }) + .collect::>() + .join("\n") + } + } + + /// Convert the provided bytes to UTF-8. + pub fn cp437_to_str(cp437: &[u8]) -> String { + cp437.iter().map(move |char| cp437_to_char(*char)).collect() + } + + /// Convert a single CP-437 character to UTF-8. + pub fn cp437_to_char(cp437: u8) -> char { + CP437_TO_UTF8[cp437 as usize] + } + + /// Convert the provided text to CP-437 bytes. + /// + /// Characters that are not available are mapped to '?'. + pub fn str_to_cp437(utf8: &str) -> Vec { + utf8.chars().map(char_to_cp437).collect() + } + + /// Convert a single UTF-8 character to CP-437. + pub fn char_to_cp437(utf8: char) -> u8 { + *UTF8_TO_CP437.get(&utf8).unwrap_or(&MISSING_CHAR_CP437) + } } #[cfg(test)] @@ -204,12 +232,23 @@ mod tests { // line break will be added assert_eq!(actual, expected); } + + #[test] + fn load_ascii_invalid() { + assert_eq!( + Err(Cp437LoadError::InvalidChar { + char: '🥶', + index: 2 + }), + Cp437Grid::load_ascii("?#🥶42", 3, false) + ); + } } #[cfg(test)] #[cfg(feature = "cp437")] mod tests_feature_cp437 { - use crate::{CharGrid, Cp437Grid}; + use super::*; #[test] fn round_trip_cp437() { @@ -218,4 +257,48 @@ mod tests_feature_cp437 { let actual = CharGrid::from(&cp437); assert_eq!(actual, utf8); } + + #[test] + fn convert_str() { + // test text from https://int10h.org/oldschool-pc-fonts/fontlist/font?ibm_bios + let utf8 = r#"A quick brown fox jumps over the lazy dog. + 0123456789 ¿?¡!`'"., <>()[]{} &@%*^#$\/ + + * Wieniläinen sioux'ta puhuva ökyzombie diggaa Åsan roquefort-tacoja. + * Ça me fait peur de fêter noël là, sur cette île bizarroïde où une mère et sa môme essaient de me tuer avec un gâteau à la cigüe brûlé. + * Zwölf Boxkämpfer jagten Eva quer über den Sylter Deich. + * El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro. + + ┌─┬─┐ ╔═╦═╗ ╒═╤═╕ ╓─╥─╖ + │ │ │ ║ ║ ║ │ │ │ ║ ║ ║ + ├─┼─┤ ╠═╬═╣ ╞═╪═╡ ╟─╫─╢ + └─┴─┘ ╚═╩═╝ ╘═╧═╛ ╙─╨─╜ + + ░░░░░ ▐▀█▀▌ .·∙•○°○•∙·. + ▒▒▒▒▒ ▐ █ ▌ ☺☻ ♥♦♣♠ ♪♫☼ + ▓▓▓▓▓ ▐▀█▀▌ $ ¢ £ ¥ ₧ + █████ ▐▄█▄▌ ◄►▲▼ ←→↑↓↕↨ + + ⌠ + │dx ≡ Σ √x²ⁿ·δx + ⌡"#; + + let cp437 = str_to_cp437(utf8); + let actual = cp437_to_str(&*cp437); + assert_eq!(utf8, actual) + } + + #[test] + fn convert_invalid() { + assert_eq!(cp437_to_char(char_to_cp437('😜')), '?'); + } + + #[test] + fn str_to_char_grid() { + let original = "Hello\r\nWorld!\n...\n"; + let grid = CharGrid::from(original); + assert_eq!(3, grid.height()); + let actual = String::from(&grid); + assert_eq!("Hello\nWorld!\n...", actual); + } } diff --git a/crates/servicepoint/src/grid.rs b/crates/servicepoint/src/grid.rs index d367d98..68fe102 100644 --- a/crates/servicepoint/src/grid.rs +++ b/crates/servicepoint/src/grid.rs @@ -76,15 +76,9 @@ pub trait Grid { /// /// When the specified position is out of bounds for this grid. fn assert_in_bounds(&self, x: usize, y: usize) { - assert!( - x < self.width(), - "cannot access index [{x}, {y}] because x is outside of bounds 0..{}", - self.width() - 1 - ); - assert!( - y < self.height(), - "cannot access index [{x}, {y}] because y is outside of bounds 0..{}", - self.height() - 1 - ); + let width = self.width(); + assert!(x < width, "cannot access index [{x}, {y}] because x is outside of bounds [0..{width})"); + let height = self.height(); + assert!(y < height, "cannot access index [{x}, {y}] because x is outside of bounds [0..{height})"); } } diff --git a/crates/servicepoint/src/lib.rs b/crates/servicepoint/src/lib.rs index fa5564e..94ac477 100644 --- a/crates/servicepoint/src/lib.rs +++ b/crates/servicepoint/src/lib.rs @@ -7,7 +7,7 @@ //! # Examples //! //! ```rust -//! use servicepoint::{Command, CompressionCode, Grid, PixelGrid}; +//! use servicepoint::{Command, CompressionCode, Grid, Bitmap}; //! //! let connection = servicepoint::Connection::open("127.0.0.1:2342") //! .expect("connection failed"); @@ -18,15 +18,15 @@ //! ``` //! //! ```rust -//! # use servicepoint::{Command, CompressionCode, Grid, PixelGrid}; +//! # use servicepoint::{Command, CompressionCode, Grid, Bitmap}; //! # let connection = servicepoint::Connection::open("127.0.0.1:2342").expect("connection failed"); //! // turn on all pixels in a grid -//! let mut pixels = PixelGrid::max_sized(); +//! let mut pixels = Bitmap::max_sized(); //! pixels.fill(true); //! //! // create command to send pixels //! let command = Command::BitmapLinearWin( -//! servicepoint::Origin::new(0, 0), +//! servicepoint::Origin::ZERO, //! pixels, //! CompressionCode::Uncompressed //! ); @@ -40,6 +40,7 @@ use std::time::Duration; pub use bitvec; use bitvec::prelude::{BitVec, Msb0}; +pub use crate::bitmap::Bitmap; pub use crate::brightness::{Brightness, BrightnessGrid}; pub use crate::command::{Command, Offset}; pub use crate::compression_code::CompressionCode; @@ -48,23 +49,22 @@ pub use crate::cp437::{CharGrid, Cp437Grid}; pub use crate::data_ref::DataRef; pub use crate::grid::Grid; pub use crate::origin::{Origin, Pixels, Tiles}; -pub use crate::pixel_grid::PixelGrid; pub use crate::primitive_grid::PrimitiveGrid; type SpBitVec = BitVec; +mod bitmap; mod brightness; mod command; mod command_code; mod compression; mod compression_code; mod connection; -mod cp437; +pub mod cp437; mod data_ref; mod grid; mod origin; pub mod packet; -mod pixel_grid; mod primitive_grid; /// size of a single tile in one dimension @@ -95,8 +95,8 @@ pub const TILE_HEIGHT: usize = 20; /// # Examples /// /// ```rust -/// # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid}; -/// let grid = PixelGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT); +/// # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, Bitmap}; +/// let grid = Bitmap::new(PIXEL_WIDTH, PIXEL_HEIGHT); /// ``` pub const PIXEL_WIDTH: usize = TILE_WIDTH * TILE_SIZE; @@ -105,8 +105,8 @@ pub const PIXEL_WIDTH: usize = TILE_WIDTH * TILE_SIZE; /// # Examples /// /// ```rust -/// # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid}; -/// let grid = PixelGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT); +/// # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, Bitmap}; +/// let grid = Bitmap::new(PIXEL_WIDTH, PIXEL_HEIGHT); /// ``` pub const PIXEL_HEIGHT: usize = TILE_HEIGHT * TILE_SIZE; @@ -119,10 +119,10 @@ pub const PIXEL_COUNT: usize = PIXEL_WIDTH * PIXEL_HEIGHT; /// /// ```rust /// # use std::time::Instant; -/// # use servicepoint::{Command, CompressionCode, FRAME_PACING, Origin, PixelGrid}; +/// # use servicepoint::{Command, CompressionCode, FRAME_PACING, Origin, Bitmap}; /// # let connection = servicepoint::Connection::open("172.23.42.29:2342") /// # .expect("connection failed"); -/// # let pixels = PixelGrid::max_sized(); +/// # let pixels = Bitmap::max_sized(); /// loop { /// let start = Instant::now(); /// diff --git a/crates/servicepoint/src/origin.rs b/crates/servicepoint/src/origin.rs index 6c0f5d2..345b89e 100644 --- a/crates/servicepoint/src/origin.rs +++ b/crates/servicepoint/src/origin.rs @@ -12,7 +12,7 @@ pub struct Origin { } impl Origin { - /// Top-left. Equivalent to `Origin::new(0, 0)`. + /// Top-left. Equivalent to `Origin::ZERO`. pub const ZERO: Self = Self { x: 0, y: 0, diff --git a/crates/servicepoint/src/packet.rs b/crates/servicepoint/src/packet.rs index e53a7a1..2b8688d 100644 --- a/crates/servicepoint/src/packet.rs +++ b/crates/servicepoint/src/packet.rs @@ -27,8 +27,8 @@ use std::mem::size_of; use crate::compression::into_compressed; use crate::{ - command_code::CommandCode, Command, CompressionCode, Grid, Offset, Origin, - PixelGrid, Pixels, Tiles, TILE_SIZE, + command_code::CommandCode, Bitmap, Command, CompressionCode, Grid, Offset, + Origin, Pixels, Tiles, TILE_SIZE, }; /// A raw header. @@ -214,7 +214,7 @@ impl From for Packet { } impl Packet { - /// Helper method for `BitMapLinear*`-Commands into [Packet] + /// Helper method for `BitmapLinear*`-Commands into [Packet] #[allow(clippy::cast_possible_truncation)] fn bitmap_linear_into_packet( command: CommandCode, @@ -239,7 +239,7 @@ impl Packet { #[allow(clippy::cast_possible_truncation)] fn bitmap_win_into_packet( origin: Origin, - pixels: PixelGrid, + pixels: Bitmap, compression: CompressionCode, ) -> Packet { debug_assert_eq!(origin.x % 8, 0); diff --git a/crates/servicepoint/src/primitive_grid.rs b/crates/servicepoint/src/primitive_grid.rs index 2b02ca3..69dcf0f 100644 --- a/crates/servicepoint/src/primitive_grid.rs +++ b/crates/servicepoint/src/primitive_grid.rs @@ -110,6 +110,34 @@ impl PrimitiveGrid { None } } + + /// Convert between PrimitiveGrid types. + /// + /// See also [Iterator::map]. + /// + /// # Examples + /// + /// Use logic written for u8s and then convert to [Brightness] values for sending in a [Command]. + /// ``` + /// # fn foo(grid: &mut PrimitiveGrid) {} + /// # use servicepoint::{Brightness, BrightnessGrid, Command, Origin, PrimitiveGrid, TILE_HEIGHT, TILE_WIDTH}; + /// let mut grid: PrimitiveGrid = PrimitiveGrid::new(TILE_WIDTH, TILE_HEIGHT); + /// foo(&mut grid); + /// let grid: BrightnessGrid = grid.map(Brightness::saturating_from); + /// let command = Command::CharBrightness(Origin::ZERO, grid); + /// ``` + pub fn map(&self, f: F) -> PrimitiveGrid + where + TConverted: PrimitiveGridType, + F: Fn(T) -> TConverted, + { + let data = self + .data_ref() + .iter() + .map(|elem| f(*elem)) + .collect::>(); + PrimitiveGrid::load(self.width(), self.height(), &data) + } } impl Grid for PrimitiveGrid { diff --git a/crates/servicepoint_binding_c/Cargo.toml b/crates/servicepoint_binding_c/Cargo.toml index 903a600..d8dd0a1 100644 --- a/crates/servicepoint_binding_c/Cargo.toml +++ b/crates/servicepoint_binding_c/Cargo.toml @@ -17,7 +17,7 @@ crate-type = ["staticlib", "cdylib", "rlib"] cbindgen = "0.27.0" [dependencies.servicepoint] -version = "0.9.1" +version = "0.10.0" path = "../servicepoint" features = ["all_compressions"] diff --git a/crates/servicepoint_binding_c/README.md b/crates/servicepoint_binding_c/README.md index 16240a9..86d38da 100644 --- a/crates/servicepoint_binding_c/README.md +++ b/crates/servicepoint_binding_c/README.md @@ -21,8 +21,8 @@ int main(void) { if (connection == NULL) return 1; - SPPixelGrid *pixels = sp_pixel_grid_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT); - sp_pixel_grid_fill(pixels, true); + SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT); + sp_bitmap_fill(pixels, true); SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed); while (sp_connection_send_command(connection, sp_command_clone(command))); diff --git a/crates/servicepoint_binding_c/cbindgen.toml b/crates/servicepoint_binding_c/cbindgen.toml index 1114264..7fc0fdf 100644 --- a/crates/servicepoint_binding_c/cbindgen.toml +++ b/crates/servicepoint_binding_c/cbindgen.toml @@ -16,7 +16,7 @@ line_endings = "LF" ############################# Codegen Options ################################## -style = "both" +style = "type" usize_is_size_t = true # this is needed because otherwise the order in the C# bindings is different on different machines @@ -31,3 +31,6 @@ all_features = true [export] include = [] exclude = [] + +[enum] +rename_variants = "QualifiedScreamingSnakeCase" diff --git a/crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h b/crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h index f431793..fec0ff0 100644 --- a/crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h +++ b/crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h @@ -8,6 +8,21 @@ #include #include +/** + * Count of possible brightness values + */ +#define SP_BRIGHTNESS_LEVELS 12 + +/** + * see [Brightness::MAX] + */ +#define SP_BRIGHTNESS_MAX 11 + +/** + * see [Brightness::MIN] + */ +#define SP_BRIGHTNESS_MIN 0 + /** * pixel count on whole screen */ @@ -49,23 +64,23 @@ enum SPCompressionCode /** * no compression */ - Uncompressed = 0, + SP_COMPRESSION_CODE_UNCOMPRESSED = 0, /** * compress using flate2 with zlib header */ - Zlib = 26490, + SP_COMPRESSION_CODE_ZLIB = 26490, /** * compress using bzip2 */ - Bzip2 = 25210, + SP_COMPRESSION_CODE_BZIP2 = 25210, /** * compress using lzma */ - Lzma = 27770, + SP_COMPRESSION_CODE_LZMA = 27770, /** * compress using Zstandard */ - Zstd = 31347, + SP_COMPRESSION_CODE_ZSTD = 31347, }; #ifndef __cplusplus typedef uint16_t SPCompressionCode; @@ -76,13 +91,27 @@ typedef uint16_t SPCompressionCode; * * # Examples * ```C - * SPBitVec vec = sp_bit_vec_new(8); - * sp_bit_vec_set(vec, 5, true); - * sp_bit_vec_free(vec); + * SPBitVec vec = sp_bitvec_new(8); + * sp_bitvec_set(vec, 5, true); + * sp_bitvec_free(vec); * ``` */ typedef struct SPBitVec SPBitVec; +/** + * 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); + * ``` + */ +typedef struct SPBitmap SPBitmap; + /** * A grid containing brightness values. * @@ -107,7 +136,7 @@ typedef struct SPBrightnessGrid SPBrightnessGrid; * * This struct and associated functions implement the UDP protocol for the display. * - * To send a `SPCommand`, use a `SPConnection`. + * To send a [SPCommand], use a [SPConnection]. * * # Examples * @@ -152,20 +181,6 @@ typedef struct SPCp437Grid SPCp437Grid; */ typedef struct SPPacket SPPacket; -/** - * A grid of pixels. - * - * # Examples - * - * ```C - * Cp437Grid grid = sp_pixel_grid_new(8, 3); - * sp_pixel_grid_fill(grid, true); - * sp_pixel_grid_set(grid, 0, 0, false); - * sp_pixel_grid_free(grid); - * ``` - */ -typedef struct SPPixelGrid SPPixelGrid; - /** * Represents a span of memory (`&mut [u8]` ) as a struct usable by C code. * @@ -181,7 +196,7 @@ typedef struct SPPixelGrid SPPixelGrid; * - 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. */ -typedef struct SPByteSlice { +typedef struct { /** * The start address of the memory */ @@ -197,51 +212,278 @@ extern "C" { #endif // __cplusplus /** - * Clones a `SPBitVec`. + * Clones a [SPBitmap]. + * + * Will never return NULL. + * + * # Panics + * + * - when `bitmap` is NULL * * # Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid `SPBitVec` - * - `bit_vec` is not written to concurrently + * - `bitmap` points to a valid [SPBitmap] + * - `bitmap` is not written to concurrently * - the returned instance is freed in some way, either by using a consuming function or - * by explicitly calling `sp_bit_vec_free`. + * by explicitly calling `sp_bitmap_free`. */ -struct SPBitVec *sp_bit_vec_clone(const struct SPBitVec *bit_vec); +SPBitmap *sp_bitmap_clone(const SPBitmap *bitmap); /** - * Sets the value of all bits in the `SPBitVec`. + * Sets the state of all pixels in the [SPBitmap]. + * + * # Arguments + * + * - `bitmap`: instance to write to + * - `value`: the value to set all pixels to + * + * # Panics + * + * - when `bitmap` is NULL + * + * # Safety + * + * The caller has to make sure that: + * + * - `bitmap` points to a valid [SPBitmap] + * - `bitmap` is not written to or read from concurrently + */ +void sp_bitmap_fill(SPBitmap *bitmap, bool value); + +/** + * Deallocates a [SPBitmap]. + * + * # Panics + * + * - when `bitmap` is NULL + * + * # Safety + * + * 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] + */ +void sp_bitmap_free(SPBitmap *bitmap); + +/** + * Gets the current value at the specified position in the [SPBitmap]. + * + * # Arguments + * + * - `bitmap`: instance to read from + * - `x` and `y`: position of the cell to read + * + * # Panics + * + * - when `bitmap` is NULL + * - when accessing `x` or `y` out of bounds + * + * # Safety + * + * The caller has to make sure that: + * + * - `bitmap` points to a valid [SPBitmap] + * - `bitmap` is not written to concurrently + */ +bool sp_bitmap_get(const SPBitmap *bitmap, size_t x, size_t y); + +/** + * Gets the height in pixels of the [SPBitmap] instance. + * + * # Arguments + * + * - `bitmap`: instance to read from + * + * # Panics + * + * - when `bitmap` is NULL + * + * # Safety + * + * The caller has to make sure that: + * + * - `bitmap` points to a valid [SPBitmap] + */ +size_t sp_bitmap_height(const SPBitmap *bitmap); + +/** + * Loads a [SPBitmap] with the specified dimensions from the provided data. + * + * # Arguments + * + * - `width`: size in pixels in x-direction + * - `height`: size in pixels in y-direction + * + * returns: [SPBitmap] that contains a copy of the provided data. Will never return NULL. + * + * # Panics + * + * - when `data` is NULL + * - when the dimensions and data size do not match exactly. + * - when the width is not dividable by 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_bitmap_free`. + */ +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. + * + * # Arguments + * + * - `width`: size in pixels in x-direction + * - `height`: size in pixels in y-direction + * + * returns: [SPBitmap] initialized to all pixels off. Will never return NULL. + * + * # Panics + * + * - when the width is not dividable by 8 + * + * # 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(size_t width, + size_t height); + +/** + * Sets the value of the specified position in the [SPBitmap]. + * + * # Arguments + * + * - `bitmap`: 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 `bitmap` is NULL + * - when accessing `x` or `y` out of bounds + * + * # Safety + * + * The caller has to make sure that: + * + * - `bitmap` points to a valid [SPBitmap] + * - `bitmap` is not written to or read from concurrently + */ +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. + * + * # Panics + * + * - when `bitmap` is NULL + * + * # Safety + * + * The caller has to make sure that: + * + * - `bitmap` points to a valid [SPBitmap] + * - 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(SPBitmap *bitmap); + +/** + * Gets the width in pixels of the [SPBitmap] instance. + * + * # Arguments + * + * - `bitmap`: instance to read from + * + * # Panics + * + * - when `bitmap` is NULL + * + * # Safety + * + * The caller has to make sure that: + * + * - `bitmap` points to a valid [SPBitmap] + */ +size_t sp_bitmap_width(const SPBitmap *bitmap); + +/** + * Clones a [SPBitVec]. + * + * returns: new [SPBitVec] instance. Will never return NULL. + * + * # Panics + * + * - when `bit_vec` is NULL + * + * # Safety + * + * The caller has to make sure that: + * + * - `bit_vec` points to a valid [SPBitVec] + * - `bit_vec` is not written to concurrently + * - the returned instance is freed in some way, either by using a consuming function or + * by explicitly calling `sp_bitvec_free`. + */ +SPBitVec *sp_bitvec_clone(const SPBitVec *bit_vec); + +/** + * Sets the value of all bits in the [SPBitVec]. * * # Arguments * * - `bit_vec`: instance to write to * - `value`: the value to set all bits to * + * # Panics + * + * - when `bit_vec` is NULL + * * # Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid `SPBitVec` + * - `bit_vec` points to a valid [SPBitVec] * - `bit_vec` is not written to or read from concurrently */ -void sp_bit_vec_fill(struct SPBitVec *bit_vec, bool value); +void sp_bitvec_fill(SPBitVec *bit_vec, bool value); /** - * Deallocates a `SPBitVec`. + * Deallocates a [SPBitVec]. + * + * # Panics + * + * - when `but_vec` is NULL * * # Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid `SPBitVec` + * - `bit_vec` points to a valid [SPBitVec] * - `bit_vec` is not used concurrently or after this call - * - `bit_vec` was not passed to another consuming function, e.g. to create a `SPCommand` + * - `bit_vec` was not passed to another consuming function, e.g. to create a [SPCommand] */ -void sp_bit_vec_free(struct SPBitVec *bit_vec); +void sp_bitvec_free(SPBitVec *bit_vec); /** - * Gets the value of a bit from the `SPBitVec`. + * Gets the value of a bit from the [SPBitVec]. * * # Arguments * @@ -252,16 +494,17 @@ void sp_bit_vec_free(struct SPBitVec *bit_vec); * * # Panics * - * When accessing `index` out of bounds. + * - when `bit_vec` is NULL + * - when accessing `index` out of bounds * * # Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid `SPBitVec` + * - `bit_vec` points to a valid [SPBitVec] * - `bit_vec` is not written to concurrently */ -bool sp_bit_vec_get(const struct SPBitVec *bit_vec, size_t index); +bool sp_bitvec_get(const SPBitVec *bit_vec, size_t index); /** * Returns true if length is 0. @@ -270,31 +513,45 @@ bool sp_bit_vec_get(const struct SPBitVec *bit_vec, size_t index); * * - `bit_vec`: instance to write to * + * # Panics + * + * - when `bit_vec` is NULL + * * # Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid `SPBitVec` + * - `bit_vec` points to a valid [SPBitVec] */ -bool sp_bit_vec_is_empty(const struct SPBitVec *bit_vec); +bool sp_bitvec_is_empty(const SPBitVec *bit_vec); /** - * Gets the length of the `SPBitVec` in bits. + * Gets the length of the [SPBitVec] in bits. * * # Arguments * * - `bit_vec`: instance to write to * + * # Panics + * + * - when `bit_vec` is NULL + * * # Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid `SPBitVec` + * - `bit_vec` points to a valid [SPBitVec] */ -size_t sp_bit_vec_len(const struct SPBitVec *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. + * Interpret the data as a series of bits and load then into a new [SPBitVec] instance. + * + * returns: [SPBitVec] instance containing data. Will never return NULL. + * + * # Panics + * + * - when `data` is NULL * * # Safety * @@ -303,35 +560,35 @@ size_t sp_bit_vec_len(const struct SPBitVec *bit_vec); * - `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_bit_vec_free`. + * by explicitly calling `sp_bitvec_free`. */ -struct SPBitVec *sp_bit_vec_load(const uint8_t *data, - size_t data_length); +SPBitVec *sp_bitvec_load(const uint8_t *data, + size_t data_length); /** - * Creates a new `SPBitVec` instance. + * Creates a new [SPBitVec] instance. * * # Arguments * * - `size`: size in bits. * - * returns: `SPBitVec` with all bits set to false. Will never return NULL. + * returns: [SPBitVec] with all bits set to false. Will never return NULL. * * # Panics * - * When `size` is not divisible by 8. + * - when `size` is not divisible by 8. * * # 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_bit_vec_free`. + * by explicitly calling `sp_bitvec_free`. */ -struct SPBitVec *sp_bit_vec_new(size_t size); +SPBitVec *sp_bitvec_new(size_t size); /** - * Sets the value of a bit in the `SPBitVec`. + * Sets the value of a bit in the [SPBitVec]. * * # Arguments * @@ -339,58 +596,67 @@ struct SPBitVec *sp_bit_vec_new(size_t size); * - `index`: the bit index to edit * - `value`: the value to set the bit to * - * returns: old value of the bit - * * # Panics * - * When accessing `index` out of bounds. + * - when `bit_vec` is NULL + * - when accessing `index` out of bounds * * # Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid `SPBitVec` + * - `bit_vec` points to a valid [SPBitVec] * - `bit_vec` is not written to or read from concurrently */ -void sp_bit_vec_set(struct SPBitVec *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. + * Gets an unsafe reference to the data of the [SPBitVec] instance. * * # Arguments * * - `bit_vec`: instance to write to * + * # Panics + * + * - when `bit_vec` is NULL + * * ## Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid `SPBitVec` - * - 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 + * - `bit_vec` points to a valid [SPBitVec] + * - 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 */ -struct SPByteSlice sp_bit_vec_unsafe_data_ref(struct SPBitVec *bit_vec); +SPByteSlice sp_bitvec_unsafe_data_ref(SPBitVec *bit_vec); /** - * Clones a `SPBrightnessGrid`. + * Clones a [SPBrightnessGrid]. * * # Arguments * * - `brightness_grid`: instance to read from * + * returns: new [SPBrightnessGrid] instance. Will never return NULL. + * + * # Panics + * + * - when `brightness_grid` is NULL + * * # Safety * * The caller has to make sure that: * - * - `brightness_grid` points to a valid `SPBrightnessGrid` + * - `brightness_grid` points to a valid [SPBrightnessGrid] * - `brightness_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_brightness_grid_free`. */ -struct SPBrightnessGrid *sp_brightness_grid_clone(const struct SPBrightnessGrid *brightness_grid); +SPBrightnessGrid *sp_brightness_grid_clone(const SPBrightnessGrid *brightness_grid); /** - * Sets the value of all cells in the `SPBrightnessGrid`. + * Sets the value of all cells in the [SPBrightnessGrid]. * * # Arguments * @@ -399,34 +665,38 @@ struct SPBrightnessGrid *sp_brightness_grid_clone(const struct SPBrightnessGrid * * # Panics * + * - when `brightness_grid` is NULL * - When providing an invalid brightness value * * # Safety * * The caller has to make sure that: * - * - `brightness_grid` points to a valid `SPBrightnessGrid` + * - `brightness_grid` points to a valid [SPBrightnessGrid] * - `brightness_grid` is not written to or read from concurrently */ -void sp_brightness_grid_fill(struct SPBrightnessGrid *brightness_grid, - uint8_t value); +void sp_brightness_grid_fill(SPBrightnessGrid *brightness_grid, uint8_t value); /** - * Deallocates a `SPBrightnessGrid`. + * Deallocates a [SPBrightnessGrid]. * * # Arguments * * - `brightness_grid`: instance to read from * + * # Panics + * + * - when `brightness_grid` is NULL + * * # Safety * * The caller has to make sure that: * - * - `brightness_grid` points to a valid `SPBrightnessGrid` + * - `brightness_grid` points to a valid [SPBrightnessGrid] * - `brightness_grid` is not used concurrently or after this call - * - `brightness_grid` was not passed to another consuming function, e.g. to create a `SPCommand` + * - `brightness_grid` was not passed to another consuming function, e.g. to create a [SPCommand] */ -void sp_brightness_grid_free(struct SPBrightnessGrid *brightness_grid); +void sp_brightness_grid_free(SPBrightnessGrid *brightness_grid); /** * Gets the current value at the specified position. @@ -436,42 +706,54 @@ void sp_brightness_grid_free(struct SPBrightnessGrid *brightness_grid); * - `brightness_grid`: instance to read from * - `x` and `y`: position of the cell to read * + * returns: value at position + * * # Panics * - * When accessing `x` or `y` out of bounds. + * - when `brightness_grid` is NULL + * - When accessing `x` or `y` out of bounds. * * # Safety * * The caller has to make sure that: * - * - `brightness_grid` points to a valid `SPBrightnessGrid` + * - `brightness_grid` points to a valid [SPBrightnessGrid] * - `brightness_grid` is not written to concurrently */ -uint8_t sp_brightness_grid_get(const struct SPBrightnessGrid *brightness_grid, +uint8_t sp_brightness_grid_get(const SPBrightnessGrid *brightness_grid, size_t x, size_t y); /** - * Gets the height of the `SPBrightnessGrid` instance. + * Gets the height of the [SPBrightnessGrid] instance. * * # Arguments * * - `brightness_grid`: instance to read from * + * returns: height + * + * # Panics + * + * - when `brightness_grid` is NULL + * * # Safety * * The caller has to make sure that: * - * - `brightness_grid` points to a valid `SPBrightnessGrid` + * - `brightness_grid` points to a valid [SPBrightnessGrid] */ -size_t sp_brightness_grid_height(const struct SPBrightnessGrid *brightness_grid); +size_t sp_brightness_grid_height(const SPBrightnessGrid *brightness_grid); /** - * Loads a `SPBrightnessGrid` with the specified dimensions from the provided data. + * Loads a [SPBrightnessGrid] with the specified dimensions from the provided data. + * + * returns: new [SPBrightnessGrid] instance. Will never return NULL. * * # Panics * - * When the provided `data_length` is not sufficient for the `height` and `width` + * - when `data` is NULL + * - when the provided `data_length` does not match `height` and `width` * * # Safety * @@ -482,15 +764,15 @@ size_t sp_brightness_grid_height(const struct SPBrightnessGrid *brightness_grid) * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_brightness_grid_free`. */ -struct SPBrightnessGrid *sp_brightness_grid_load(size_t width, - size_t height, - const uint8_t *data, - size_t data_length); +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. + * Creates a new [SPBrightnessGrid] with the specified dimensions. * - * returns: `SPBrightnessGrid` initialized to 0. Will never return NULL. + * returns: [SPBrightnessGrid] initialized to 0. Will never return NULL. * * # Safety * @@ -499,11 +781,11 @@ struct SPBrightnessGrid *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`. */ -struct SPBrightnessGrid *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`. + * Sets the value of the specified position in the [SPBrightnessGrid]. * * # Arguments * @@ -515,6 +797,7 @@ struct SPBrightnessGrid *sp_brightness_grid_new(size_t width, * * # Panics * + * - when `brightness_grid` is NULL * - When accessing `x` or `y` out of bounds. * - When providing an invalid brightness value * @@ -522,45 +805,57 @@ struct SPBrightnessGrid *sp_brightness_grid_new(size_t width, * * The caller has to make sure that: * - * - `brightness_grid` points to a valid `SPBitVec` + * - `brightness_grid` points to a valid [SPBitVec] * - `brightness_grid` is not written to or read from concurrently */ -void sp_brightness_grid_set(struct SPBrightnessGrid *brightness_grid, +void sp_brightness_grid_set(SPBrightnessGrid *brightness_grid, size_t x, size_t y, uint8_t value); /** - * Gets an unsafe reference to the data of the `SPBrightnessGrid` instance. + * Gets an unsafe reference to the data of the [SPBrightnessGrid] instance. * * # Arguments * * - `brightness_grid`: instance to read from * - * ## Safety + * returns: slice of bytes underlying the `brightness_grid`. * - * The caller has to make sure that: + * # Panics * - * - `brightness_grid` points to a valid `SPBrightnessGrid` - * - 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 - */ -struct SPByteSlice sp_brightness_grid_unsafe_data_ref(struct SPBrightnessGrid *brightness_grid); - -/** - * Gets the width of the `SPBrightnessGrid` instance. - * - * # Arguments - * - * - `brightness_grid`: instance to read from + * - when `brightness_grid` is NULL * * # Safety * * The caller has to make sure that: * - * - `brightness_grid` points to a valid `SPBrightnessGrid` + * - `brightness_grid` points to a valid [SPBrightnessGrid] + * - 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 */ -size_t sp_brightness_grid_width(const struct SPBrightnessGrid *brightness_grid); +SPByteSlice sp_brightness_grid_unsafe_data_ref(SPBrightnessGrid *brightness_grid); + +/** + * Gets the width of the [SPBrightnessGrid] instance. + * + * # Arguments + * + * - `brightness_grid`: instance to read from + * + * returns: width + * + * # Panics + * + * - when `brightness_grid` is NULL + * + * # Safety + * + * The caller has to make sure that: + * + * - `brightness_grid` points to a valid [SPBrightnessGrid] + */ +size_t sp_brightness_grid_width(const SPBrightnessGrid *brightness_grid); /** * Set pixel data starting at the pixel offset on screen. @@ -568,25 +863,30 @@ size_t sp_brightness_grid_width(const struct SPBrightnessGrid *brightness_grid); * The screen will continuously overwrite more pixel data without regarding the offset, meaning * once the starting row is full, overwriting will continue on column 0. * - * The contained `SPBitVec` is always uncompressed. + * The contained [SPBitVec] is always uncompressed. * - * The passed `SPBitVec` gets consumed. + * The passed [SPBitVec] gets consumed. * - * Returns: a new `Command::BitmapLinear` instance. Will never return NULL. + * Returns: a new [Command::BitmapLinear] instance. Will never return NULL. + * + * # Panics + * + * - when `bit_vec` is null + * - when `compression_code` is not a valid value * * # Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid instance of `SPBitVec` + * - `bit_vec` points to a valid instance of [SPBitVec] * - `bit_vec` is not used concurrently or after this call * - `compression` matches one of the allowed enum values - * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_bitmap_linear(size_t offset, - struct SPBitVec *bit_vec, - SPCompressionCode 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. @@ -594,25 +894,30 @@ struct SPCommand *sp_command_bitmap_linear(size_t offset, * The screen will continuously overwrite more pixel data without regarding the offset, meaning * once the starting row is full, overwriting will continue on column 0. * - * The contained `SPBitVec` is always uncompressed. + * The contained [SPBitVec] is always uncompressed. * - * The passed `SPBitVec` gets consumed. + * The passed [SPBitVec] gets consumed. * - * Returns: a new `Command::BitmapLinearAnd` instance. Will never return NULL. + * Returns: a new [Command::BitmapLinearAnd] instance. Will never return NULL. + * + * # Panics + * + * - when `bit_vec` is null + * - when `compression_code` is not a valid value * * # Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid instance of `SPBitVec` + * - `bit_vec` points to a valid instance of [SPBitVec] * - `bit_vec` is not used concurrently or after this call * - `compression` matches one of the allowed enum values - * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_bitmap_linear_and(size_t offset, - struct SPBitVec *bit_vec, - SPCompressionCode 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. @@ -620,47 +925,57 @@ struct SPCommand *sp_command_bitmap_linear_and(size_t offset, * The screen will continuously overwrite more pixel data without regarding the offset, meaning * once the starting row is full, overwriting will continue on column 0. * - * The contained `SPBitVec` is always uncompressed. + * The contained [SPBitVec] is always uncompressed. * - * The passed `SPBitVec` gets consumed. + * The passed [SPBitVec] gets consumed. * - * Returns: a new `Command::BitmapLinearOr` instance. Will never return NULL. + * Returns: a new [Command::BitmapLinearOr] instance. Will never return NULL. + * + * # Panics + * + * - when `bit_vec` is null + * - when `compression_code` is not a valid value * * # Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid instance of `SPBitVec` + * - `bit_vec` points to a valid instance of [SPBitVec] * - `bit_vec` is not used concurrently or after this call * - `compression` matches one of the allowed enum values - * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_bitmap_linear_or(size_t offset, - struct SPBitVec *bit_vec, - SPCompressionCode compression); +SPCommand *sp_command_bitmap_linear_or(size_t offset, + SPBitVec *bit_vec, + SPCompressionCode compression); /** * Sets a window of pixels to the specified values. * - * The passed `SPPixelGrid` gets consumed. + * The passed [SPBitmap] gets consumed. * - * Returns: a new `Command::BitmapLinearWin` instance. Will never return NULL. + * Returns: a new [Command::BitmapLinearWin] instance. Will never return NULL. + * + * # Panics + * + * - when `bitmap` is null + * - when `compression_code` is not a valid value * * # Safety * * The caller has to make sure that: * - * - `pixel_grid` points to a valid instance of `SPPixelGrid` - * - `pixel_grid` is not used concurrently or after this call + * - `bitmap` points to a valid instance of [SPBitmap] + * - `bitmap` is not used concurrently or after this call * - `compression` matches one of the allowed enum values - * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_bitmap_linear_win(size_t x, - size_t y, - struct SPPixelGrid *pixel_grid, - SPCompressionCode compression_code); +SPCommand *sp_command_bitmap_linear_win(size_t x, + size_t y, + SPBitmap *bitmap, + SPCompressionCode compression_code); /** * Set pixel data according to a xor-mask starting at the offset. @@ -668,30 +983,35 @@ struct SPCommand *sp_command_bitmap_linear_win(size_t x, * The screen will continuously overwrite more pixel data without regarding the offset, meaning * once the starting row is full, overwriting will continue on column 0. * - * The contained `SPBitVec` is always uncompressed. + * The contained [SPBitVec] is always uncompressed. * - * The passed `SPBitVec` gets consumed. + * The passed [SPBitVec] gets consumed. * - * Returns: a new `Command::BitmapLinearXor` instance. Will never return NULL. + * Returns: a new [Command::BitmapLinearXor] instance. Will never return NULL. + * + * # Panics + * + * - when `bit_vec` is null + * - when `compression_code` is not a valid value * * # Safety * * The caller has to make sure that: * - * - `bit_vec` points to a valid instance of `SPBitVec` + * - `bit_vec` points to a valid instance of [SPBitVec] * - `bit_vec` is not used concurrently or after this call * - `compression` matches one of the allowed enum values - * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_bitmap_linear_xor(size_t offset, - struct SPBitVec *bit_vec, - SPCompressionCode 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. * - * Returns: a new `Command::Brightness` instance. Will never return NULL. + * Returns: a new [Command::Brightness] instance. Will never return NULL. * * # Panics * @@ -701,37 +1021,41 @@ struct SPCommand *sp_command_bitmap_linear_xor(size_t offset, * * The caller has to make sure that: * - * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *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. * - * The passed `SPBrightnessGrid` gets consumed. + * The passed [SPBrightnessGrid] gets consumed. * - * Returns: a new `Command::CharBrightness` instance. Will never return NULL. + * Returns: a new [Command::CharBrightness] 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 `SPBrightnessGrid` + * - `grid` points to a valid instance of [SPBrightnessGrid] * - `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 + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_char_brightness(size_t x, - size_t y, - struct SPBrightnessGrid *grid); +SPCommand *sp_command_char_brightness(size_t x, + size_t y, + SPBrightnessGrid *grid); /** * Set all pixels to the off state. * * Does not affect brightness. * - * Returns: a new `Command::Clear` instance. Will never return NULL. + * Returns: a new [Command::Clear] instance. Will never return NULL. * * # Examples * @@ -743,49 +1067,54 @@ struct SPCommand *sp_command_char_brightness(size_t x, * * The caller has to make sure that: * - * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_clear(void); +SPCommand *sp_command_clear(void); /** - * Clones a `SPCommand` instance. + * Clones a [SPCommand] instance. + * + * returns: new [SPCommand] instance. Will never return NULL. + * + * # Panics + * + * - when `command` is NULL * * # Safety * * The caller has to make sure that: * - * - `command` points to a valid instance of `SPCommand` + * - `command` points to a valid instance of [SPCommand] * - `command` is not written to concurrently - * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_clone(const struct SPCommand *command); +SPCommand *sp_command_clone(const SPCommand *command); /** * Show text on the screen. * - *
- * The library does not currently convert between UTF-8 and CP-437. - * Because Rust expects UTF-8 strings, it might be necessary to only send ASCII for now. - *
+ * The passed [SPCp437Grid] gets consumed. * - * The passed `SPCp437Grid` gets consumed./// + * Returns: a new [Command::Cp437Data] instance. Will never return NULL. * - * Returns: a new `Command::Cp437Data` 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 `SPCp437Grid` + * - `grid` points to a valid instance of [SPCp437Grid] * - `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 + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_cp437_data(size_t x, - size_t y, - struct SPCp437Grid *grid); +SPCommand *sp_command_cp437_data(size_t x, + size_t y, + SPCp437Grid *grid); /** * A yet-to-be-tested command. @@ -796,13 +1125,13 @@ struct SPCommand *sp_command_cp437_data(size_t x, * * The caller has to make sure that: * - * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_fade_out(void); +SPCommand *sp_command_fade_out(void); /** - * Deallocates a `SPCommand`. + * Deallocates a [SPCommand]. * * # Examples * @@ -811,71 +1140,83 @@ struct SPCommand *sp_command_fade_out(void); * sp_command_free(c); * ``` * + * # Panics + * + * - when `command` is NULL + * * # Safety * * The caller has to make sure that: * - * - `command` points to a valid `SPCommand` + * - `command` points to a valid [SPCommand] * - `command` is not used concurrently or after this call - * - `command` was not passed to another consuming function, e.g. to create a `SPPacket` + * - `command` was not passed to another consuming function, e.g. to create a [SPPacket] */ -void sp_command_free(struct SPCommand *command); +void sp_command_free(SPCommand *command); /** * Kills the udp daemon on the display, which usually results in a restart. * * Please do not send this in your normal program flow. * - * Returns: a new `Command::HardReset` instance. Will never return NULL. + * Returns: a new [Command::HardReset] instance. Will never return NULL. * * # Safety * * The caller has to make sure that: * - * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_hard_reset(void); +SPCommand *sp_command_hard_reset(void); /** - * Tries to turn a `SPPacket` into a `SPCommand`. + * Tries to turn a [SPPacket] into a [SPCommand]. * * The packet is deallocated in the process. * - * Returns: pointer to new `SPCommand` instance or NULL + * Returns: pointer to new [SPCommand] instance or NULL if parsing failed. + * + * # Panics + * + * - when `packet` is NULL * * # Safety * * The caller has to make sure that: * - * - `SPPacket` points to a valid instance of `SPPacket` - * - `SPPacket` is not used concurrently or after this call + * - [SPPacket] points to a valid instance of [SPPacket] + * - [SPPacket] is not used concurrently or after this call * - the result is checked for NULL - * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_command_free`. */ -struct SPCommand *sp_command_try_from_packet(struct SPPacket *packet); +SPCommand *sp_command_try_from_packet(SPPacket *packet); /** - * Closes and deallocates a `SPConnection`. + * Closes and deallocates a [SPConnection]. + * + * # Panics + * + * - when `connection` is NULL * * # Safety * * The caller has to make sure that: * - * - `connection` points to a valid `SPConnection` + * - `connection` points to a valid [SPConnection] * - `connection` is not used concurrently or after this call */ -void sp_connection_free(struct SPConnection *connection); +void sp_connection_free(SPConnection *connection); /** - * Creates a new instance of `SPConnection`. + * Creates a new instance of [SPConnection]. * * returns: NULL if connection fails, or connected instance * * # Panics * - * Bad string encoding + * - when `host` is null or an invalid host * * # Safety * @@ -884,89 +1225,111 @@ void sp_connection_free(struct SPConnection *connection); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_connection_free`. */ -struct SPConnection *sp_connection_open(const char *host); +SPConnection *sp_connection_open(const char *host); /** - * Sends a `SPCommand` to the display using the `SPConnection`. + * Sends a [SPCommand] to the display using the [SPConnection]. * * The passed `command` gets consumed. * * returns: true in case of success * + * # Panics + * + * - when `connection` is NULL + * - when `command` is NULL + * * # Safety * * The caller has to make sure that: * - * - `connection` points to a valid instance of `SPConnection` - * - `command` points to a valid instance of `SPPacket` + * - `connection` points to a valid instance of [SPConnection] + * - `command` points to a valid instance of [SPPacket] * - `command` is not used concurrently or after this call */ -bool sp_connection_send_command(const struct SPConnection *connection, - struct SPCommand *command); +bool sp_connection_send_command(const SPConnection *connection, + SPCommand *command); /** - * Sends a `SPPacket` to the display using the `SPConnection`. + * Sends a [SPPacket] to the display using the [SPConnection]. * * The passed `packet` gets consumed. * * returns: true in case of success * + * # Panics + * + * - when `connection` is NULL + * - when `packet` is NULL + * * # Safety * * The caller has to make sure that: * - * - `connection` points to a valid instance of `SPConnection` - * - `packet` points to a valid instance of `SPPacket` + * - `connection` points to a valid instance of [SPConnection] + * - `packet` points to a valid instance of [SPPacket] * - `packet` is not used concurrently or after this call */ -bool sp_connection_send_packet(const struct SPConnection *connection, - struct SPPacket *packet); +bool sp_connection_send_packet(const SPConnection *connection, + SPPacket *packet); /** - * Clones a `SPCp437Grid`. + * Clones a [SPCp437Grid]. * * Will never return NULL. * + * # Panics + * + * - when `cp437_grid` is NULL + * * # Safety * * The caller has to make sure that: * - * - `cp437_grid` points to a valid `SPCp437Grid` + * - `cp437_grid` points to a valid [SPCp437Grid] * - `cp437_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_cp437_grid_free`. */ -struct SPCp437Grid *sp_cp437_grid_clone(const struct SPCp437Grid *cp437_grid); +SPCp437Grid *sp_cp437_grid_clone(const SPCp437Grid *cp437_grid); /** - * Sets the value of all cells in the `SPCp437Grid`. + * Sets the value of all cells in the [SPCp437Grid]. * * # Arguments * * - `cp437_grid`: instance to write to * - `value`: the value to set all cells to * + * # Panics + * + * - when `cp437_grid` is NULL + * * # Safety * * The caller has to make sure that: * - * - `cp437_grid` points to a valid `SPCp437Grid` + * - `cp437_grid` points to a valid [SPCp437Grid] * - `cp437_grid` is not written to or read from concurrently */ -void sp_cp437_grid_fill(struct SPCp437Grid *cp437_grid, uint8_t value); +void sp_cp437_grid_fill(SPCp437Grid *cp437_grid, uint8_t value); /** - * Deallocates a `SPCp437Grid`. + * Deallocates a [SPCp437Grid]. + * + * # Panics + * + * - when `cp437_grid` is NULL * * # Safety * * The caller has to make sure that: * - * - `cp437_grid` points to a valid `SPCp437Grid` + * - `cp437_grid` points to a valid [SPCp437Grid] * - `cp437_grid` is not used concurrently or after cp437_grid call - * - `cp437_grid` was not passed to another consuming function, e.g. to create a `SPCommand` + * - `cp437_grid` was not passed to another consuming function, e.g. to create a [SPCommand] */ -void sp_cp437_grid_free(struct SPCp437Grid *cp437_grid); +void sp_cp437_grid_free(SPCp437Grid *cp437_grid); /** * Gets the current value at the specified position. @@ -978,42 +1341,46 @@ void sp_cp437_grid_free(struct SPCp437Grid *cp437_grid); * * # Panics * - * When accessing `x` or `y` out of bounds. + * - when `cp437_grid` is NULL + * - when accessing `x` or `y` out of bounds * * # Safety * * The caller has to make sure that: * - * - `cp437_grid` points to a valid `SPCp437Grid` + * - `cp437_grid` points to a valid [SPCp437Grid] * - `cp437_grid` is not written to concurrently */ -uint8_t sp_cp437_grid_get(const struct SPCp437Grid *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. + * Gets the height of the [SPCp437Grid] instance. * * # Arguments * * - `cp437_grid`: instance to read from * + * # Panics + * + * - when `cp437_grid` is NULL + * * # Safety * * The caller has to make sure that: * - * - `cp437_grid` points to a valid `SPCp437Grid` + * - `cp437_grid` points to a valid [SPCp437Grid] */ -size_t sp_cp437_grid_height(const struct SPCp437Grid *cp437_grid); +size_t sp_cp437_grid_height(const SPCp437Grid *cp437_grid); /** - * Loads a `SPCp437Grid` with the specified dimensions from the provided data. + * Loads a [SPCp437Grid] with the specified dimensions from the provided data. * * Will never return NULL. * * # Panics * - * When the provided `data_length` is not sufficient for the `height` and `width` + * - when `data` is NULL + * - when the provided `data_length` does not match `height` and `width` * * # Safety * @@ -1024,15 +1391,15 @@ size_t sp_cp437_grid_height(const struct SPCp437Grid *cp437_grid); * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_cp437_grid_free`. */ -struct SPCp437Grid *sp_cp437_grid_load(size_t width, - size_t height, - const uint8_t *data, - size_t data_length); +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. + * Creates a new [SPCp437Grid] with the specified dimensions. * - * returns: `SPCp437Grid` initialized to 0. + * returns: [SPCp437Grid] initialized to 0. Will never return NULL. * * # Safety * @@ -1041,11 +1408,11 @@ struct SPCp437Grid *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`. */ -struct SPCp437Grid *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`. + * Sets the value of the specified position in the [SPCp437Grid]. * * # Arguments * @@ -1057,302 +1424,136 @@ struct SPCp437Grid *sp_cp437_grid_new(size_t width, * * # Panics * - * When accessing `x` or `y` out of bounds. + * - when `cp437_grid` is NULL + * - when accessing `x` or `y` out of bounds * * # Safety * * The caller has to make sure that: * - * - `cp437_grid` points to a valid `SPBitVec` + * - `cp437_grid` points to a valid [SPBitVec] * - `cp437_grid` is not written to or read from concurrently */ -void sp_cp437_grid_set(struct SPCp437Grid *cp437_grid, +void sp_cp437_grid_set(SPCp437Grid *cp437_grid, size_t x, size_t y, uint8_t value); /** - * Gets an unsafe reference to the data of the `SPCp437Grid` instance. + * Gets an unsafe reference to the data of the [SPCp437Grid] instance. * * Will never return NULL. * + * # Panics + * + * - when `cp437_grid` is NULL + * * ## Safety * * The caller has to make sure that: * - * - `cp437_grid` points to a valid `SPCp437Grid` - * - 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 + * - `cp437_grid` points to a valid [SPCp437Grid] + * - 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 */ -struct SPByteSlice sp_cp437_grid_unsafe_data_ref(struct SPCp437Grid *cp437_grid); +SPByteSlice sp_cp437_grid_unsafe_data_ref(SPCp437Grid *cp437_grid); /** - * Gets the width of the `SPCp437Grid` instance. + * Gets the width of the [SPCp437Grid] instance. * * # Arguments * * - `cp437_grid`: instance to read from * + * # Panics + * + * - when `cp437_grid` is NULL + * * # Safety * * The caller has to make sure that: * - * - `cp437_grid` points to a valid `SPCp437Grid` + * - `cp437_grid` points to a valid [SPCp437Grid] */ -size_t sp_cp437_grid_width(const struct SPCp437Grid *cp437_grid); +size_t sp_cp437_grid_width(const SPCp437Grid *cp437_grid); /** - * Clones a `SPPacket`. + * Clones a [SPPacket]. * * Will never return NULL. * + * # Panics + * + * - when `packet` is NULL + * * # Safety * * The caller has to make sure that: * - * - `packet` points to a valid `SPPacket` + * - `packet` points to a valid [SPPacket] * - `packet` is not written to concurrently * - the returned instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_packet_free`. */ -struct SPPacket *sp_packet_clone(const struct SPPacket *packet); +SPPacket *sp_packet_clone(const SPPacket *packet); /** - * Deallocates a `SPPacket`. + * Deallocates a [SPPacket]. + * + * # Panics + * + * - when `sp_packet_free` is NULL * * # Safety * * The caller has to make sure that: * - * - `packet` points to a valid `SPPacket` + * - `packet` points to a valid [SPPacket] * - `packet` is not used concurrently or after this call */ -void sp_packet_free(struct SPPacket *packet); +void sp_packet_free(SPPacket *packet); /** - * Turns a `SPCommand` into a `SPPacket`. - * The `SPCommand` gets consumed. + * Turns a [SPCommand] into a [SPPacket]. + * The [SPCommand] gets consumed. * * Will never return NULL. * + * # Panics + * + * - when `command` is NULL + * * # Safety * * The caller has to make sure that: * - * - `SPCommand` points to a valid instance of `SPCommand` - * - `SPCommand` is not used concurrently or after this call - * - the returned `SPPacket` instance is freed in some way, either by using a consuming function or + * - [SPCommand] points to a valid instance of [SPCommand] + * - [SPCommand] is not used concurrently or after this call + * - the returned [SPPacket] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_packet_free`. */ -struct SPPacket *sp_packet_from_command(struct SPCommand *command); +SPPacket *sp_packet_from_command(SPCommand *command); /** - * Tries to load a `SPPacket` from the passed array with the specified length. + * Tries to load a [SPPacket] from the passed array with the specified length. * * returns: NULL in case of an error, pointer to the allocated packet otherwise * + * # Panics + * + * - when `data` is NULL + * * # Safety * * The caller has to make sure that: * * - `data` points to a valid memory region of at least `length` bytes * - `data` is not written to concurrently - * - the returned `SPPacket` instance is freed in some way, either by using a consuming function or + * - the returned [SPPacket] instance is freed in some way, either by using a consuming function or * by explicitly calling `sp_packet_free`. */ -struct SPPacket *sp_packet_try_load(const uint8_t *data, - size_t length); - -/** - * Clones a `SPPixelGrid`. - * - * Will never return NULL. - * - * # Safety - * - * The caller has to make sure that: - * - * - `pixel_grid` points to a valid `SPPixelGrid` - * - `pixel_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_pixel_grid_free`. - */ -struct SPPixelGrid *sp_pixel_grid_clone(const struct SPPixelGrid *pixel_grid); - -/** - * Sets the state of all pixels in the `SPPixelGrid`. - * - * # Arguments - * - * - `pixel_grid`: instance to write to - * - `value`: the value to set all pixels to - * - * # Safety - * - * The caller has to make sure that: - * - * - `pixel_grid` points to a valid `SPPixelGrid` - * - `pixel_grid` is not written to or read from concurrently - */ -void sp_pixel_grid_fill(struct SPPixelGrid *pixel_grid, bool value); - -/** - * Deallocates a `SPPixelGrid`. - * - * # Safety - * - * The caller has to make sure that: - * - * - `pixel_grid` points to a valid `SPPixelGrid` - * - `pixel_grid` is not used concurrently or after pixel_grid call - * - `pixel_grid` was not passed to another consuming function, e.g. to create a `SPCommand` - */ -void sp_pixel_grid_free(struct SPPixelGrid *pixel_grid); - -/** - * Gets the current value at the specified position in the `SPPixelGrid`. - * - * # Arguments - * - * - `pixel_grid`: instance to read from - * - `x` and `y`: position of the cell to read - * - * # Panics - * - * When accessing `x` or `y` out of bounds. - * - * # Safety - * - * The caller has to make sure that: - * - * - `pixel_grid` points to a valid `SPPixelGrid` - * - `pixel_grid` is not written to concurrently - */ -bool sp_pixel_grid_get(const struct SPPixelGrid *pixel_grid, - size_t x, - size_t y); - -/** - * Gets the height in pixels of the `SPPixelGrid` instance. - * - * # Arguments - * - * - `pixel_grid`: instance to read from - * - * # Safety - * - * The caller has to make sure that: - * - * - `pixel_grid` points to a valid `SPPixelGrid` - */ -size_t sp_pixel_grid_height(const struct SPPixelGrid *pixel_grid); - -/** - * Loads a `SPPixelGrid` with the specified dimensions from the provided data. - * - * # Arguments - * - * - `width`: size in pixels in x-direction - * - `height`: size in pixels in y-direction - * - * returns: `SPPixelGrid` that contains a copy of the provided data. Will never return NULL. - * - * # Panics - * - * - when the dimensions and data size do not match exactly. - * - when the width is not dividable by 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_pixel_grid_free`. - */ -struct SPPixelGrid *sp_pixel_grid_load(size_t width, - size_t height, - const uint8_t *data, - size_t data_length); - -/** - * Creates a new `SPPixelGrid` with the specified dimensions. - * - * # Arguments - * - * - `width`: size in pixels in x-direction - * - `height`: size in pixels in y-direction - * - * returns: `SPPixelGrid` initialized to all pixels off. Will never return NULL. - * - * # Panics - * - * - when the width is not dividable by 8 - * - * # 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_pixel_grid_free`. - */ -struct SPPixelGrid *sp_pixel_grid_new(size_t width, - size_t height); - -/** - * Sets the value of the specified position in the `SPPixelGrid`. - * - * # Arguments - * - * - `pixel_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 accessing `x` or `y` out of bounds. - * - * # Safety - * - * The caller has to make sure that: - * - * - `pixel_grid` points to a valid `SPPixelGrid` - * - `pixel_grid` is not written to or read from concurrently - */ -void sp_pixel_grid_set(struct SPPixelGrid *pixel_grid, - size_t x, - size_t y, - bool value); - -/** - * Gets an unsafe reference to the data of the `SPPixelGrid` instance. - * - * ## Safety - * - * The caller has to make sure that: - * - * - `pixel_grid` points to a valid `SPPixelGrid` - * - the returned memory range is never accessed after the passed `SPPixelGrid` has been freed - * - the returned memory range is never accessed concurrently, either via the `SPPixelGrid` or directly - */ -struct SPByteSlice sp_pixel_grid_unsafe_data_ref(struct SPPixelGrid *pixel_grid); - -/** - * Gets the width in pixels of the `SPPixelGrid` instance. - * - * # Arguments - * - * - `pixel_grid`: instance to read from - * - * # Safety - * - * The caller has to make sure that: - * - * - `pixel_grid` points to a valid `SPPixelGrid` - */ -size_t sp_pixel_grid_width(const struct SPPixelGrid *pixel_grid); +SPPacket *sp_packet_try_load(const uint8_t *data, + size_t length); #ifdef __cplusplus } // extern "C" diff --git a/crates/servicepoint_binding_c/examples/lang_c/src/main.c b/crates/servicepoint_binding_c/examples/lang_c/src/main.c index 5054286..e84e510 100644 --- a/crates/servicepoint_binding_c/examples/lang_c/src/main.c +++ b/crates/servicepoint_binding_c/examples/lang_c/src/main.c @@ -6,10 +6,10 @@ int main(void) { if (connection == NULL) return 1; - SPPixelGrid *pixels = sp_pixel_grid_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT); - sp_pixel_grid_fill(pixels, true); + SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT); + sp_bitmap_fill(pixels, true); - SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed); + SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, SP_COMPRESSION_CODE_UNCOMPRESSED); while (sp_connection_send_command(connection, sp_command_clone(command))); sp_command_free(command); diff --git a/crates/servicepoint_binding_c/src/bitmap.rs b/crates/servicepoint_binding_c/src/bitmap.rs new file mode 100644 index 0000000..b327fd2 --- /dev/null +++ b/crates/servicepoint_binding_c/src/bitmap.rs @@ -0,0 +1,281 @@ +//! C functions for interacting with [SPBitmap]s +//! +//! prefix `sp_bitmap_` + +use std::ptr::NonNull; +use servicepoint::{DataRef, Grid}; + +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 +/// +/// - `width`: size in pixels in x-direction +/// - `height`: size in pixels in y-direction +/// +/// returns: [SPBitmap] initialized to all pixels off. Will never return NULL. +/// +/// # Panics +/// +/// - when the width is not dividable by 8 +/// +/// # 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`. +#[no_mangle] +pub unsafe extern "C" fn sp_bitmap_new( + width: usize, + height: usize, +) -> NonNull { + let result = Box::new(SPBitmap(servicepoint::Bitmap::new( + width, height, + ))); + NonNull::from(Box::leak(result)) +} + +/// Loads a [SPBitmap] with the specified dimensions from the provided data. +/// +/// # Arguments +/// +/// - `width`: size in pixels in x-direction +/// - `height`: size in pixels in y-direction +/// +/// returns: [SPBitmap] that contains a copy of the provided data. Will never return NULL. +/// +/// # Panics +/// +/// - when `data` is NULL +/// - when the dimensions and data size do not match exactly. +/// - when the width is not dividable by 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_bitmap_free`. +#[no_mangle] +pub unsafe extern "C" fn sp_bitmap_load( + width: usize, + height: usize, + data: *const u8, + data_length: usize, +) -> NonNull { + assert!(!data.is_null()); + let data = std::slice::from_raw_parts(data, data_length); + let result = Box::new(SPBitmap(servicepoint::Bitmap::load( + width, height, data, + ))); + NonNull::from(Box::leak(result)) +} + +/// Clones a [SPBitmap]. +/// +/// Will never return NULL. +/// +/// # Panics +/// +/// - when `bitmap` is NULL +/// +/// # Safety +/// +/// The caller has to make sure that: +/// +/// - `bitmap` points to a valid [SPBitmap] +/// - `bitmap` is not written to concurrently +/// - 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_clone( + bitmap: *const SPBitmap, +) -> NonNull { + assert!(!bitmap.is_null()); + let result = Box::new(SPBitmap((*bitmap).0.clone())); + NonNull::from(Box::leak(result)) +} + +/// Deallocates a [SPBitmap]. +/// +/// # Panics +/// +/// - when `bitmap` is NULL +/// +/// # Safety +/// +/// 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] +#[no_mangle] +pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) { + assert!(!bitmap.is_null()); + _ = Box::from_raw(bitmap); +} + +/// Gets the current value at the specified position in the [SPBitmap]. +/// +/// # Arguments +/// +/// - `bitmap`: instance to read from +/// - `x` and `y`: position of the cell to read +/// +/// # Panics +/// +/// - when `bitmap` is NULL +/// - when accessing `x` or `y` out of bounds +/// +/// # Safety +/// +/// The caller has to make sure that: +/// +/// - `bitmap` points to a valid [SPBitmap] +/// - `bitmap` is not written to concurrently +#[no_mangle] +pub unsafe extern "C" fn sp_bitmap_get( + bitmap: *const SPBitmap, + x: usize, + y: usize, +) -> bool { + assert!(!bitmap.is_null()); + (*bitmap).0.get(x, y) +} + +/// Sets the value of the specified position in the [SPBitmap]. +/// +/// # Arguments +/// +/// - `bitmap`: 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 `bitmap` is NULL +/// - when accessing `x` or `y` out of bounds +/// +/// # Safety +/// +/// The caller has to make sure that: +/// +/// - `bitmap` points to a valid [SPBitmap] +/// - `bitmap` is not written to or read from concurrently +#[no_mangle] +pub unsafe extern "C" fn sp_bitmap_set( + bitmap: *mut SPBitmap, + x: usize, + y: usize, + value: bool, +) { + assert!(!bitmap.is_null()); + (*bitmap).0.set(x, y, value); +} + +/// Sets the state of all pixels in the [SPBitmap]. +/// +/// # Arguments +/// +/// - `bitmap`: instance to write to +/// - `value`: the value to set all pixels to +/// +/// # Panics +/// +/// - when `bitmap` is NULL +/// +/// # Safety +/// +/// The caller has to make sure that: +/// +/// - `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: *mut SPBitmap, value: bool) { + assert!(!bitmap.is_null()); + (*bitmap).0.fill(value); +} + +/// Gets the width in pixels of the [SPBitmap] instance. +/// +/// # Arguments +/// +/// - `bitmap`: instance to read from +/// +/// # Panics +/// +/// - when `bitmap` is NULL +/// +/// # Safety +/// +/// The caller has to make sure that: +/// +/// - `bitmap` points to a valid [SPBitmap] +#[no_mangle] +pub unsafe extern "C" fn sp_bitmap_width(bitmap: *const SPBitmap) -> usize { + assert!(!bitmap.is_null()); + (*bitmap).0.width() +} + +/// Gets the height in pixels of the [SPBitmap] instance. +/// +/// # Arguments +/// +/// - `bitmap`: instance to read from +/// +/// # Panics +/// +/// - when `bitmap` is NULL +/// +/// # Safety +/// +/// The caller has to make sure that: +/// +/// - `bitmap` points to a valid [SPBitmap] +#[no_mangle] +pub unsafe extern "C" fn sp_bitmap_height(bitmap: *const SPBitmap) -> usize { + assert!(!bitmap.is_null()); + (*bitmap).0.height() +} + +/// Gets an unsafe reference to the data of the [SPBitmap] instance. +/// +/// # Panics +/// +/// - when `bitmap` is NULL +/// +/// # Safety +/// +/// The caller has to make sure that: +/// +/// - `bitmap` points to a valid [SPBitmap] +/// - 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 +#[no_mangle] +pub unsafe extern "C" fn sp_bitmap_unsafe_data_ref( + bitmap: *mut SPBitmap, +) -> SPByteSlice { + assert!(!bitmap.is_null()); + let data = (*bitmap).0.data_ref_mut(); + SPByteSlice { + start: NonNull::new(data.as_mut_ptr_range().start).unwrap(), + length: data.len(), + } +} diff --git a/crates/servicepoint_binding_c/src/bit_vec.rs b/crates/servicepoint_binding_c/src/bitvec.rs similarity index 52% rename from crates/servicepoint_binding_c/src/bit_vec.rs rename to crates/servicepoint_binding_c/src/bitvec.rs index d1b353c..7f2258a 100644 --- a/crates/servicepoint_binding_c/src/bit_vec.rs +++ b/crates/servicepoint_binding_c/src/bitvec.rs @@ -1,7 +1,8 @@ -//! C functions for interacting with `SPBitVec`s +//! C functions for interacting with [SPBitVec]s //! -//! prefix `sp_bit_vec_` +//! prefix `sp_bitvec_` +use std::ptr::NonNull; use crate::SPByteSlice; use servicepoint::bitvec::prelude::{BitVec, Msb0}; @@ -9,9 +10,9 @@ use servicepoint::bitvec::prelude::{BitVec, Msb0}; /// /// # Examples /// ```C -/// SPBitVec vec = sp_bit_vec_new(8); -/// sp_bit_vec_set(vec, 5, true); -/// sp_bit_vec_free(vec); +/// SPBitVec vec = sp_bitvec_new(8); +/// sp_bitvec_set(vec, 5, true); +/// sp_bitvec_free(vec); /// ``` pub struct SPBitVec(BitVec); @@ -33,30 +34,37 @@ impl Clone for SPBitVec { } } -/// Creates a new `SPBitVec` instance. +/// Creates a new [SPBitVec] instance. /// /// # Arguments /// /// - `size`: size in bits. /// -/// returns: `SPBitVec` with all bits set to false. Will never return NULL. +/// returns: [SPBitVec] with all bits set to false. Will never return NULL. /// /// # Panics /// -/// When `size` is not divisible by 8. +/// - when `size` is not divisible by 8. /// /// # 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_bit_vec_free`. +/// by explicitly calling `sp_bitvec_free`. #[no_mangle] -pub unsafe extern "C" fn sp_bit_vec_new(size: usize) -> *mut SPBitVec { - Box::into_raw(Box::new(SPBitVec(BitVec::repeat(false, size)))) +pub unsafe extern "C" fn sp_bitvec_new(size: usize) -> NonNull { + let result = Box::new(SPBitVec(BitVec::repeat(false, size))); + NonNull::from(Box::leak(result)) } -/// Interpret the data as a series of bits and load then into a new `SPBitVec` instance. +/// Interpret the data as a series of bits and load then into a new [SPBitVec] instance. +/// +/// returns: [SPBitVec] instance containing data. Will never return NULL. +/// +/// # Panics +/// +/// - when `data` is NULL /// /// # Safety /// @@ -65,48 +73,63 @@ pub unsafe extern "C" fn sp_bit_vec_new(size: usize) -> *mut SPBitVec { /// - `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_bit_vec_free`. +/// by explicitly calling `sp_bitvec_free`. #[no_mangle] -pub unsafe extern "C" fn sp_bit_vec_load( +pub unsafe extern "C" fn sp_bitvec_load( data: *const u8, data_length: usize, -) -> *mut SPBitVec { +) -> NonNull { + assert!(!data.is_null()); let data = std::slice::from_raw_parts(data, data_length); - Box::into_raw(Box::new(SPBitVec(BitVec::from_slice(data)))) + let result = Box::new(SPBitVec(BitVec::from_slice(data))); + NonNull::from(Box::leak(result)) } -/// Clones a `SPBitVec`. +/// Clones a [SPBitVec]. +/// +/// returns: new [SPBitVec] instance. Will never return NULL. +/// +/// # Panics +/// +/// - when `bit_vec` is NULL /// /// # Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid `SPBitVec` +/// - `bit_vec` points to a valid [SPBitVec] /// - `bit_vec` is not written to concurrently /// - the returned instance is freed in some way, either by using a consuming function or -/// by explicitly calling `sp_bit_vec_free`. +/// by explicitly calling `sp_bitvec_free`. #[no_mangle] -pub unsafe extern "C" fn sp_bit_vec_clone( +pub unsafe extern "C" fn sp_bitvec_clone( bit_vec: *const SPBitVec, -) -> *mut SPBitVec { - Box::into_raw(Box::new((*bit_vec).clone())) +) -> NonNull { + assert!(!bit_vec.is_null()); + let result = Box::new((*bit_vec).clone()); + NonNull::from(Box::leak(result)) } -/// Deallocates a `SPBitVec`. +/// Deallocates a [SPBitVec]. +/// +/// # Panics +/// +/// - when `but_vec` is NULL /// /// # Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid `SPBitVec` +/// - `bit_vec` points to a valid [SPBitVec] /// - `bit_vec` is not used concurrently or after this call -/// - `bit_vec` was not passed to another consuming function, e.g. to create a `SPCommand` +/// - `bit_vec` was not passed to another consuming function, e.g. to create a [SPCommand] #[no_mangle] -pub unsafe extern "C" fn sp_bit_vec_free(bit_vec: *mut SPBitVec) { +pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) { + assert!(!bit_vec.is_null()); _ = Box::from_raw(bit_vec); } -/// Gets the value of a bit from the `SPBitVec`. +/// Gets the value of a bit from the [SPBitVec]. /// /// # Arguments /// @@ -117,23 +140,25 @@ pub unsafe extern "C" fn sp_bit_vec_free(bit_vec: *mut SPBitVec) { /// /// # Panics /// -/// When accessing `index` out of bounds. +/// - when `bit_vec` is NULL +/// - when accessing `index` out of bounds /// /// # Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid `SPBitVec` +/// - `bit_vec` points to a valid [SPBitVec] /// - `bit_vec` is not written to concurrently #[no_mangle] -pub unsafe extern "C" fn sp_bit_vec_get( +pub unsafe extern "C" fn sp_bitvec_get( bit_vec: *const SPBitVec, index: usize, ) -> bool { + assert!(!bit_vec.is_null()); *(*bit_vec).0.get(index).unwrap() } -/// Sets the value of a bit in the `SPBitVec`. +/// Sets the value of a bit in the [SPBitVec]. /// /// # Arguments /// @@ -141,58 +166,68 @@ pub unsafe extern "C" fn sp_bit_vec_get( /// - `index`: the bit index to edit /// - `value`: the value to set the bit to /// -/// returns: old value of the bit -/// /// # Panics /// -/// When accessing `index` out of bounds. +/// - when `bit_vec` is NULL +/// - when accessing `index` out of bounds /// /// # Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid `SPBitVec` +/// - `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_bit_vec_set( +pub unsafe extern "C" fn sp_bitvec_set( bit_vec: *mut SPBitVec, index: usize, value: bool, ) { + assert!(!bit_vec.is_null()); (*bit_vec).0.set(index, value) } -/// Sets the value of all bits in the `SPBitVec`. +/// Sets the value of all bits in the [SPBitVec]. /// /// # Arguments /// /// - `bit_vec`: instance to write to /// - `value`: the value to set all bits to /// +/// # Panics +/// +/// - when `bit_vec` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid `SPBitVec` +/// - `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_bit_vec_fill(bit_vec: *mut SPBitVec, value: bool) { +pub unsafe extern "C" fn sp_bitvec_fill(bit_vec: *mut SPBitVec, value: bool) { + assert!(!bit_vec.is_null()); (*bit_vec).0.fill(value) } -/// Gets the length of the `SPBitVec` in bits. +/// Gets the length of the [SPBitVec] in bits. /// /// # Arguments /// /// - `bit_vec`: instance to write to /// +/// # Panics +/// +/// - when `bit_vec` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid `SPBitVec` +/// - `bit_vec` points to a valid [SPBitVec] #[no_mangle] -pub unsafe extern "C" fn sp_bit_vec_len(bit_vec: *const SPBitVec) -> usize { +pub unsafe extern "C" fn sp_bitvec_len(bit_vec: *const SPBitVec) -> usize { + assert!(!bit_vec.is_null()); (*bit_vec).0.len() } @@ -202,36 +237,46 @@ pub unsafe extern "C" fn sp_bit_vec_len(bit_vec: *const SPBitVec) -> usize { /// /// - `bit_vec`: instance to write to /// +/// # Panics +/// +/// - when `bit_vec` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid `SPBitVec` +/// - `bit_vec` points to a valid [SPBitVec] #[no_mangle] -pub unsafe extern "C" fn sp_bit_vec_is_empty(bit_vec: *const SPBitVec) -> bool { +pub unsafe extern "C" fn sp_bitvec_is_empty(bit_vec: *const SPBitVec) -> bool { + assert!(!bit_vec.is_null()); (*bit_vec).0.is_empty() } -/// Gets an unsafe reference to the data of the `SPBitVec` instance. +/// Gets an unsafe reference to the data of the [SPBitVec] instance. /// /// # Arguments /// /// - `bit_vec`: instance to write to /// +/// # Panics +/// +/// - when `bit_vec` is NULL +/// /// ## Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid `SPBitVec` -/// - 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 +/// - `bit_vec` points to a valid [SPBitVec] +/// - 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 #[no_mangle] -pub unsafe extern "C" fn sp_bit_vec_unsafe_data_ref( +pub unsafe extern "C" fn sp_bitvec_unsafe_data_ref( bit_vec: *mut SPBitVec, ) -> SPByteSlice { + assert!(!bit_vec.is_null()); let data = (*bit_vec).0.as_raw_mut_slice(); SPByteSlice { - start: data.as_mut_ptr_range().start, + start: NonNull::new(data.as_mut_ptr_range().start).unwrap(), length: data.len(), } } diff --git a/crates/servicepoint_binding_c/src/brightness_grid.rs b/crates/servicepoint_binding_c/src/brightness_grid.rs index a34ecf2..3c94b57 100644 --- a/crates/servicepoint_binding_c/src/brightness_grid.rs +++ b/crates/servicepoint_binding_c/src/brightness_grid.rs @@ -1,10 +1,19 @@ -//! C functions for interacting with `SPBrightnessGrid`s +//! C functions for interacting with [SPBrightnessGrid]s //! //! prefix `sp_brightness_grid_` use crate::SPByteSlice; use servicepoint::{Brightness, DataRef, Grid, PrimitiveGrid}; +use std::convert::Into; use std::intrinsics::transmute; +use std::ptr::NonNull; + +/// see [Brightness::MIN] +pub const SP_BRIGHTNESS_MIN: u8 = 0; +/// see [Brightness::MAX] +pub const SP_BRIGHTNESS_MAX: u8 = 11; +/// Count of possible brightness values +pub const SP_BRIGHTNESS_LEVELS: u8 = 12; /// A grid containing brightness values. /// @@ -21,17 +30,12 @@ use std::intrinsics::transmute; /// SPCommand command = sp_command_char_brightness(grid); /// sp_connection_free(connection); /// ``` +#[derive(Clone)] pub struct SPBrightnessGrid(pub(crate) servicepoint::BrightnessGrid); -impl Clone for SPBrightnessGrid { - fn clone(&self) -> Self { - SPBrightnessGrid(self.0.clone()) - } -} - -/// Creates a new `SPBrightnessGrid` with the specified dimensions. +/// Creates a new [SPBrightnessGrid] with the specified dimensions. /// -/// returns: `SPBrightnessGrid` initialized to 0. Will never return NULL. +/// returns: [SPBrightnessGrid] initialized to 0. Will never return NULL. /// /// # Safety /// @@ -43,17 +47,21 @@ impl Clone for SPBrightnessGrid { pub unsafe extern "C" fn sp_brightness_grid_new( width: usize, height: usize, -) -> *mut SPBrightnessGrid { - Box::into_raw(Box::new(SPBrightnessGrid( +) -> NonNull { + let result = Box::new(SPBrightnessGrid( servicepoint::BrightnessGrid::new(width, height), - ))) + )); + NonNull::from(Box::leak(result)) } -/// Loads a `SPBrightnessGrid` with the specified dimensions from the provided data. +/// Loads a [SPBrightnessGrid] with the specified dimensions from the provided data. +/// +/// returns: new [SPBrightnessGrid] instance. Will never return NULL. /// /// # Panics /// -/// When the provided `data_length` is not sufficient for the `height` and `width` +/// - when `data` is NULL +/// - when the provided `data_length` does not match `height` and `width` /// /// # Safety /// @@ -69,52 +77,67 @@ pub unsafe extern "C" fn sp_brightness_grid_load( height: usize, data: *const u8, data_length: usize, -) -> *mut SPBrightnessGrid { +) -> NonNull { + assert!(!data.is_null()); let data = std::slice::from_raw_parts(data, data_length); let grid = PrimitiveGrid::load(width, height, data); let grid = servicepoint::BrightnessGrid::try_from(grid) .expect("invalid brightness value"); - Box::into_raw(Box::new(SPBrightnessGrid(grid))) + let result = Box::new(SPBrightnessGrid(grid)); + NonNull::from(Box::leak(result)) } -/// Clones a `SPBrightnessGrid`. +/// Clones a [SPBrightnessGrid]. /// /// # Arguments /// /// - `brightness_grid`: instance to read from /// +/// returns: new [SPBrightnessGrid] instance. Will never return NULL. +/// +/// # Panics +/// +/// - when `brightness_grid` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `brightness_grid` points to a valid `SPBrightnessGrid` +/// - `brightness_grid` points to a valid [SPBrightnessGrid] /// - `brightness_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_brightness_grid_free`. #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_clone( brightness_grid: *const SPBrightnessGrid, -) -> *mut SPBrightnessGrid { - Box::into_raw(Box::new((*brightness_grid).clone())) +) -> NonNull { + assert!(!brightness_grid.is_null()); + let result = Box::new((*brightness_grid).clone()); + NonNull::from(Box::leak(result)) } -/// Deallocates a `SPBrightnessGrid`. +/// Deallocates a [SPBrightnessGrid]. /// /// # Arguments /// /// - `brightness_grid`: instance to read from /// +/// # Panics +/// +/// - when `brightness_grid` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `brightness_grid` points to a valid `SPBrightnessGrid` +/// - `brightness_grid` points to a valid [SPBrightnessGrid] /// - `brightness_grid` is not used concurrently or after this call -/// - `brightness_grid` was not passed to another consuming function, e.g. to create a `SPCommand` +/// - `brightness_grid` was not passed to another consuming function, e.g. to create a [SPCommand] #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_free( brightness_grid: *mut SPBrightnessGrid, ) { + assert!(!brightness_grid.is_null()); _ = Box::from_raw(brightness_grid); } @@ -125,15 +148,18 @@ pub unsafe extern "C" fn sp_brightness_grid_free( /// - `brightness_grid`: instance to read from /// - `x` and `y`: position of the cell to read /// +/// returns: value at position +/// /// # Panics /// -/// When accessing `x` or `y` out of bounds. +/// - when `brightness_grid` is NULL +/// - When accessing `x` or `y` out of bounds. /// /// # Safety /// /// The caller has to make sure that: /// -/// - `brightness_grid` points to a valid `SPBrightnessGrid` +/// - `brightness_grid` points to a valid [SPBrightnessGrid] /// - `brightness_grid` is not written to concurrently #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_get( @@ -141,10 +167,11 @@ pub unsafe extern "C" fn sp_brightness_grid_get( x: usize, y: usize, ) -> u8 { + assert!(!brightness_grid.is_null()); (*brightness_grid).0.get(x, y).into() } -/// Sets the value of the specified position in the `SPBrightnessGrid`. +/// Sets the value of the specified position in the [SPBrightnessGrid]. /// /// # Arguments /// @@ -156,6 +183,7 @@ pub unsafe extern "C" fn sp_brightness_grid_get( /// /// # Panics /// +/// - when `brightness_grid` is NULL /// - When accessing `x` or `y` out of bounds. /// - When providing an invalid brightness value /// @@ -163,7 +191,7 @@ pub unsafe extern "C" fn sp_brightness_grid_get( /// /// The caller has to make sure that: /// -/// - `brightness_grid` points to a valid `SPBitVec` +/// - `brightness_grid` points to a valid [SPBitVec] /// - `brightness_grid` is not written to or read from concurrently #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_set( @@ -172,12 +200,13 @@ pub unsafe extern "C" fn sp_brightness_grid_set( y: usize, value: u8, ) { + assert!(!brightness_grid.is_null()); let brightness = Brightness::try_from(value).expect("invalid brightness value"); (*brightness_grid).0.set(x, y, brightness); } -/// Sets the value of all cells in the `SPBrightnessGrid`. +/// Sets the value of all cells in the [SPBrightnessGrid]. /// /// # Arguments /// @@ -186,83 +215,106 @@ pub unsafe extern "C" fn sp_brightness_grid_set( /// /// # Panics /// +/// - when `brightness_grid` is NULL /// - When providing an invalid brightness value /// /// # Safety /// /// The caller has to make sure that: /// -/// - `brightness_grid` points to a valid `SPBrightnessGrid` +/// - `brightness_grid` points to a valid [SPBrightnessGrid] /// - `brightness_grid` is not written to or read from concurrently #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_fill( brightness_grid: *mut SPBrightnessGrid, value: u8, ) { + assert!(!brightness_grid.is_null()); let brightness = Brightness::try_from(value).expect("invalid brightness value"); (*brightness_grid).0.fill(brightness); } -/// Gets the width of the `SPBrightnessGrid` instance. +/// Gets the width of the [SPBrightnessGrid] instance. /// /// # Arguments /// /// - `brightness_grid`: instance to read from /// +/// returns: width +/// +/// # Panics +/// +/// - when `brightness_grid` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `brightness_grid` points to a valid `SPBrightnessGrid` +/// - `brightness_grid` points to a valid [SPBrightnessGrid] #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_width( brightness_grid: *const SPBrightnessGrid, ) -> usize { + assert!(!brightness_grid.is_null()); (*brightness_grid).0.width() } -/// Gets the height of the `SPBrightnessGrid` instance. +/// Gets the height of the [SPBrightnessGrid] instance. /// /// # Arguments /// /// - `brightness_grid`: instance to read from /// +/// returns: height +/// +/// # Panics +/// +/// - when `brightness_grid` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `brightness_grid` points to a valid `SPBrightnessGrid` +/// - `brightness_grid` points to a valid [SPBrightnessGrid] #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_height( brightness_grid: *const SPBrightnessGrid, ) -> usize { + assert!(!brightness_grid.is_null()); (*brightness_grid).0.height() } -/// Gets an unsafe reference to the data of the `SPBrightnessGrid` instance. +/// Gets an unsafe reference to the data of the [SPBrightnessGrid] instance. /// /// # Arguments /// /// - `brightness_grid`: instance to read from /// -/// ## Safety +/// returns: slice of bytes underlying the `brightness_grid`. +/// +/// # Panics +/// +/// - when `brightness_grid` is NULL +/// +/// # Safety /// /// The caller has to make sure that: /// -/// - `brightness_grid` points to a valid `SPBrightnessGrid` -/// - 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 +/// - `brightness_grid` points to a valid [SPBrightnessGrid] +/// - 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 #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref( brightness_grid: *mut SPBrightnessGrid, ) -> SPByteSlice { + assert!(!brightness_grid.is_null()); assert_eq!(core::mem::size_of::(), 1); - let data = (*brightness_grid).0.data_ref_mut(); + // this assumes more about the memory layout than rust guarantees. yikes! let data: &mut [u8] = transmute(data); SPByteSlice { - start: data.as_mut_ptr_range().start, + start: NonNull::new(data.as_mut_ptr_range().start).unwrap(), length: data.len(), } } diff --git a/crates/servicepoint_binding_c/src/byte_slice.rs b/crates/servicepoint_binding_c/src/byte_slice.rs index fbdda2a..678a5d7 100644 --- a/crates/servicepoint_binding_c/src/byte_slice.rs +++ b/crates/servicepoint_binding_c/src/byte_slice.rs @@ -1,5 +1,7 @@ //! FFI slice helper +use std::ptr::NonNull; + #[repr(C)] /// Represents a span of memory (`&mut [u8]` ) as a struct usable by C code. /// @@ -16,7 +18,7 @@ /// will try to free the memory of a potentially separate allocator. pub struct SPByteSlice { /// The start address of the memory - pub start: *mut u8, + pub start: NonNull, /// The amount of memory in bytes pub length: usize, } diff --git a/crates/servicepoint_binding_c/src/command.rs b/crates/servicepoint_binding_c/src/command.rs index d98b99f..a4ebc1a 100644 --- a/crates/servicepoint_binding_c/src/command.rs +++ b/crates/servicepoint_binding_c/src/command.rs @@ -1,21 +1,21 @@ -//! C functions for interacting with `SPCommand`s +//! C functions for interacting with [SPCommand]s //! //! prefix `sp_command_` -use std::ptr::null_mut; +use std::ptr::{null_mut, NonNull}; use servicepoint::{Brightness, Origin}; use crate::{ - SPBitVec, SPBrightnessGrid, SPCompressionCode, SPCp437Grid, SPPacket, - SPPixelGrid, + SPBitVec, SPBitmap, SPBrightnessGrid, SPCompressionCode, SPCp437Grid, + SPPacket, }; /// A low-level display command. /// /// This struct and associated functions implement the UDP protocol for the display. /// -/// To send a `SPCommand`, use a `SPConnection`. +/// To send a [SPCommand], use a [SPConnection]. /// /// # Examples /// @@ -31,20 +31,24 @@ impl Clone for SPCommand { } } -/// Tries to turn a `SPPacket` into a `SPCommand`. +/// Tries to turn a [SPPacket] into a [SPCommand]. /// /// The packet is deallocated in the process. /// -/// Returns: pointer to new `SPCommand` instance or NULL +/// Returns: pointer to new [SPCommand] instance or NULL if parsing failed. +/// +/// # Panics +/// +/// - when `packet` is NULL /// /// # Safety /// /// The caller has to make sure that: /// -/// - `SPPacket` points to a valid instance of `SPPacket` -/// - `SPPacket` is not used concurrently or after this call +/// - [SPPacket] points to a valid instance of [SPPacket] +/// - [SPPacket] is not used concurrently or after this call /// - the result is checked for NULL -/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or +/// - 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_try_from_packet( @@ -57,28 +61,36 @@ pub unsafe extern "C" fn sp_command_try_from_packet( } } -/// Clones a `SPCommand` instance. +/// Clones a [SPCommand] instance. +/// +/// returns: new [SPCommand] instance. Will never return NULL. +/// +/// # Panics +/// +/// - when `command` is NULL /// /// # Safety /// /// The caller has to make sure that: /// -/// - `command` points to a valid instance of `SPCommand` +/// - `command` points to a valid instance of [SPCommand] /// - `command` is not written to concurrently -/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or +/// - 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_clone( command: *const SPCommand, -) -> *mut SPCommand { - Box::into_raw(Box::new((*command).clone())) +) -> NonNull { + assert!(!command.is_null()); + let result = Box::new((*command).clone()); + NonNull::from(Box::leak(result)) } /// Set all pixels to the off state. /// /// Does not affect brightness. /// -/// Returns: a new `Command::Clear` instance. Will never return NULL. +/// Returns: a new [Command::Clear] instance. Will never return NULL. /// /// # Examples /// @@ -90,28 +102,30 @@ pub unsafe extern "C" fn sp_command_clone( /// /// The caller has to make sure that: /// -/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or +/// - 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() -> *mut SPCommand { - Box::into_raw(Box::new(SPCommand(servicepoint::Command::Clear))) +pub unsafe extern "C" fn sp_command_clear() -> NonNull { + let result = Box::new(SPCommand(servicepoint::Command::Clear)); + NonNull::from(Box::leak(result)) } /// Kills the udp daemon on the display, which usually results in a restart. /// /// Please do not send this in your normal program flow. /// -/// Returns: a new `Command::HardReset` instance. Will never return NULL. +/// Returns: a new [Command::HardReset] instance. Will never return NULL. /// /// # Safety /// /// The caller has to make sure that: /// -/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or +/// - 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() -> *mut SPCommand { - Box::into_raw(Box::new(SPCommand(servicepoint::Command::HardReset))) +pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull { + let result = Box::new(SPCommand(servicepoint::Command::HardReset)); + NonNull::from(Box::leak(result)) } /// A yet-to-be-tested command. @@ -122,16 +136,17 @@ pub unsafe extern "C" fn sp_command_hard_reset() -> *mut SPCommand { /// /// The caller has to make sure that: /// -/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or +/// - 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() -> *mut SPCommand { - Box::into_raw(Box::new(SPCommand(servicepoint::Command::FadeOut))) +pub unsafe extern "C" fn sp_command_fade_out() -> NonNull { + let result = Box::new(SPCommand(servicepoint::Command::FadeOut)); + NonNull::from(Box::leak(result)) } /// Set the brightness of all tiles to the same value. /// -/// Returns: a new `Command::Brightness` instance. Will never return NULL. +/// Returns: a new [Command::Brightness] instance. Will never return NULL. /// /// # Panics /// @@ -141,44 +156,50 @@ pub unsafe extern "C" fn sp_command_fade_out() -> *mut SPCommand { /// /// The caller has to make sure that: /// -/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or +/// - 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_brightness( brightness: u8, -) -> *mut SPCommand { +) -> NonNull { let brightness = Brightness::try_from(brightness).expect("invalid brightness"); - Box::into_raw(Box::new(SPCommand(servicepoint::Command::Brightness( - brightness, - )))) + let result = Box::new(SPCommand( + servicepoint::Command::Brightness(brightness), + )); + NonNull::from(Box::leak(result)) } /// Set the brightness of individual tiles in a rectangular area of the display. /// -/// The passed `SPBrightnessGrid` gets consumed. +/// The passed [SPBrightnessGrid] gets consumed. /// -/// Returns: a new `Command::CharBrightness` instance. Will never return NULL. +/// Returns: a new [Command::CharBrightness] 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 `SPBrightnessGrid` +/// - `grid` points to a valid instance of [SPBrightnessGrid] /// - `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 +/// - 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_char_brightness( x: usize, y: usize, grid: *mut SPBrightnessGrid, -) -> *mut SPCommand { +) -> NonNull { + assert!(!grid.is_null()); let byte_grid = *Box::from_raw(grid); - Box::into_raw(Box::new(SPCommand(servicepoint::Command::CharBrightness( - Origin::new(x, y), - byte_grid.0, - )))) + let result = Box::new(SPCommand( + servicepoint::Command::CharBrightness(Origin::new(x, y), byte_grid.0), + )); + NonNull::from(Box::leak(result)) } /// Set pixel data starting at the pixel offset on screen. @@ -186,33 +207,42 @@ pub unsafe extern "C" fn sp_command_char_brightness( /// The screen will continuously overwrite more pixel data without regarding the offset, meaning /// once the starting row is full, overwriting will continue on column 0. /// -/// The contained `SPBitVec` is always uncompressed. +/// The contained [SPBitVec] is always uncompressed. /// -/// The passed `SPBitVec` gets consumed. +/// The passed [SPBitVec] gets consumed. /// -/// Returns: a new `Command::BitmapLinear` instance. Will never return NULL. +/// Returns: a new [Command::BitmapLinear] instance. Will never return NULL. +/// +/// # Panics +/// +/// - when `bit_vec` is null +/// - when `compression_code` is not a valid value /// /// # Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid instance of `SPBitVec` +/// - `bit_vec` points to a valid instance of [SPBitVec] /// - `bit_vec` is not used concurrently or after this call /// - `compression` matches one of the allowed enum values -/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or +/// - 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_bitmap_linear( offset: usize, bit_vec: *mut SPBitVec, compression: SPCompressionCode, -) -> *mut SPCommand { +) -> NonNull { + assert!(!bit_vec.is_null()); let bit_vec = *Box::from_raw(bit_vec); - Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinear( - offset, - bit_vec.into(), - compression.try_into().expect("invalid compression code"), - )))) + let result = Box::new(SPCommand( + servicepoint::Command::BitmapLinear( + offset, + bit_vec.into(), + compression.try_into().expect("invalid compression code"), + ), + )); + NonNull::from(Box::leak(result)) } /// Set pixel data according to an and-mask starting at the offset. @@ -220,33 +250,42 @@ pub unsafe extern "C" fn sp_command_bitmap_linear( /// The screen will continuously overwrite more pixel data without regarding the offset, meaning /// once the starting row is full, overwriting will continue on column 0. /// -/// The contained `SPBitVec` is always uncompressed. +/// The contained [SPBitVec] is always uncompressed. /// -/// The passed `SPBitVec` gets consumed. +/// The passed [SPBitVec] gets consumed. /// -/// Returns: a new `Command::BitmapLinearAnd` instance. Will never return NULL. +/// Returns: a new [Command::BitmapLinearAnd] instance. Will never return NULL. +/// +/// # Panics +/// +/// - when `bit_vec` is null +/// - when `compression_code` is not a valid value /// /// # Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid instance of `SPBitVec` +/// - `bit_vec` points to a valid instance of [SPBitVec] /// - `bit_vec` is not used concurrently or after this call /// - `compression` matches one of the allowed enum values -/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or +/// - 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_bitmap_linear_and( offset: usize, bit_vec: *mut SPBitVec, compression: SPCompressionCode, -) -> *mut SPCommand { +) -> NonNull { + assert!(!bit_vec.is_null()); let bit_vec = *Box::from_raw(bit_vec); - Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearAnd( - offset, - bit_vec.into(), - compression.try_into().expect("invalid compression code"), - )))) + let result = Box::new(SPCommand( + servicepoint::Command::BitmapLinearAnd( + offset, + bit_vec.into(), + compression.try_into().expect("invalid compression code"), + ), + )); + NonNull::from(Box::leak(result)) } /// Set pixel data according to an or-mask starting at the offset. @@ -254,33 +293,42 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_and( /// The screen will continuously overwrite more pixel data without regarding the offset, meaning /// once the starting row is full, overwriting will continue on column 0. /// -/// The contained `SPBitVec` is always uncompressed. +/// The contained [SPBitVec] is always uncompressed. /// -/// The passed `SPBitVec` gets consumed. +/// The passed [SPBitVec] gets consumed. /// -/// Returns: a new `Command::BitmapLinearOr` instance. Will never return NULL. +/// Returns: a new [Command::BitmapLinearOr] instance. Will never return NULL. +/// +/// # Panics +/// +/// - when `bit_vec` is null +/// - when `compression_code` is not a valid value /// /// # Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid instance of `SPBitVec` +/// - `bit_vec` points to a valid instance of [SPBitVec] /// - `bit_vec` is not used concurrently or after this call /// - `compression` matches one of the allowed enum values -/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or +/// - 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_bitmap_linear_or( offset: usize, bit_vec: *mut SPBitVec, compression: SPCompressionCode, -) -> *mut SPCommand { +) -> NonNull { + assert!(!bit_vec.is_null()); let bit_vec = *Box::from_raw(bit_vec); - Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearOr( - offset, - bit_vec.into(), - compression.try_into().expect("invalid compression code"), - )))) + let result = Box::new(SPCommand( + servicepoint::Command::BitmapLinearOr( + offset, + bit_vec.into(), + compression.try_into().expect("invalid compression code"), + ), + )); + NonNull::from(Box::leak(result)) } /// Set pixel data according to a xor-mask starting at the offset. @@ -288,100 +336,118 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_or( /// The screen will continuously overwrite more pixel data without regarding the offset, meaning /// once the starting row is full, overwriting will continue on column 0. /// -/// The contained `SPBitVec` is always uncompressed. +/// The contained [SPBitVec] is always uncompressed. /// -/// The passed `SPBitVec` gets consumed. +/// The passed [SPBitVec] gets consumed. /// -/// Returns: a new `Command::BitmapLinearXor` instance. Will never return NULL. +/// Returns: a new [Command::BitmapLinearXor] instance. Will never return NULL. +/// +/// # Panics +/// +/// - when `bit_vec` is null +/// - when `compression_code` is not a valid value /// /// # Safety /// /// The caller has to make sure that: /// -/// - `bit_vec` points to a valid instance of `SPBitVec` +/// - `bit_vec` points to a valid instance of [SPBitVec] /// - `bit_vec` is not used concurrently or after this call /// - `compression` matches one of the allowed enum values -/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or +/// - 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_bitmap_linear_xor( offset: usize, bit_vec: *mut SPBitVec, compression: SPCompressionCode, -) -> *mut SPCommand { +) -> NonNull { + assert!(!bit_vec.is_null()); let bit_vec = *Box::from_raw(bit_vec); - Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearXor( - offset, - bit_vec.into(), - compression.try_into().expect("invalid compression code"), - )))) + let result = Box::new(SPCommand( + servicepoint::Command::BitmapLinearXor( + offset, + bit_vec.into(), + compression.try_into().expect("invalid compression code"), + ), + )); + NonNull::from(Box::leak(result)) } /// Show text on the screen. /// -///
-/// The library does not currently convert between UTF-8 and CP-437. -/// Because Rust expects UTF-8 strings, it might be necessary to only send ASCII for now. -///
+/// The passed [SPCp437Grid] gets consumed. /// -/// The passed `SPCp437Grid` gets consumed./// +/// Returns: a new [Command::Cp437Data] instance. Will never return NULL. /// -/// Returns: a new `Command::Cp437Data` 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 `SPCp437Grid` +/// - `grid` points to a valid instance of [SPCp437Grid] /// - `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 +/// - 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_cp437_data( x: usize, y: usize, grid: *mut SPCp437Grid, -) -> *mut SPCommand { +) -> NonNull { + assert!(!grid.is_null()); let grid = *Box::from_raw(grid); - Box::into_raw(Box::new(SPCommand(servicepoint::Command::Cp437Data( - Origin::new(x, y), - grid.0, - )))) + let result = Box::new(SPCommand( + servicepoint::Command::Cp437Data(Origin::new(x, y), grid.0), + )); + NonNull::from(Box::leak(result)) } /// Sets a window of pixels to the specified values. /// -/// The passed `SPPixelGrid` gets consumed. +/// The passed [SPBitmap] gets consumed. /// -/// Returns: a new `Command::BitmapLinearWin` instance. Will never return NULL. +/// Returns: a new [Command::BitmapLinearWin] instance. Will never return NULL. +/// +/// # Panics +/// +/// - when `bitmap` is null +/// - when `compression_code` is not a valid value /// /// # Safety /// /// The caller has to make sure that: /// -/// - `pixel_grid` points to a valid instance of `SPPixelGrid` -/// - `pixel_grid` is not used concurrently or after this call +/// - `bitmap` points to a valid instance of [SPBitmap] +/// - `bitmap` is not used concurrently or after this call /// - `compression` matches one of the allowed enum values -/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or +/// - 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_bitmap_linear_win( x: usize, y: usize, - pixel_grid: *mut SPPixelGrid, + bitmap: *mut SPBitmap, compression_code: SPCompressionCode, -) -> *mut SPCommand { - let byte_grid = (*Box::from_raw(pixel_grid)).0; - Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearWin( - Origin::new(x, y), - byte_grid, - compression_code - .try_into() - .expect("invalid compression code"), - )))) +) -> NonNull { + assert!(!bitmap.is_null()); + let byte_grid = (*Box::from_raw(bitmap)).0; + let result = Box::new(SPCommand( + servicepoint::Command::BitmapLinearWin( + Origin::new(x, y), + byte_grid, + compression_code + .try_into() + .expect("invalid compression code"), + ), + )); + NonNull::from(Box::leak(result)) } -/// Deallocates a `SPCommand`. +/// Deallocates a [SPCommand]. /// /// # Examples /// @@ -390,14 +456,19 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_win( /// sp_command_free(c); /// ``` /// +/// # Panics +/// +/// - when `command` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `command` points to a valid `SPCommand` +/// - `command` points to a valid [SPCommand] /// - `command` is not used concurrently or after this call -/// - `command` was not passed to another consuming function, e.g. to create a `SPPacket` +/// - `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: *mut SPCommand) { + assert!(!command.is_null()); _ = Box::from_raw(command); } diff --git a/crates/servicepoint_binding_c/src/connection.rs b/crates/servicepoint_binding_c/src/connection.rs index 846b607..3f54438 100644 --- a/crates/servicepoint_binding_c/src/connection.rs +++ b/crates/servicepoint_binding_c/src/connection.rs @@ -1,4 +1,4 @@ -//! C functions for interacting with `SPConnection`s +//! C functions for interacting with [SPConnection]s //! //! prefix `sp_connection_` @@ -18,13 +18,13 @@ use crate::{SPCommand, SPPacket}; /// ``` pub struct SPConnection(pub(crate) servicepoint::Connection); -/// Creates a new instance of `SPConnection`. +/// Creates a new instance of [SPConnection]. /// /// returns: NULL if connection fails, or connected instance /// /// # Panics /// -/// Bad string encoding +/// - when `host` is null or an invalid host /// /// # Safety /// @@ -36,6 +36,7 @@ pub struct SPConnection(pub(crate) servicepoint::Connection); pub unsafe extern "C" fn sp_connection_open( host: *const c_char, ) -> *mut SPConnection { + assert!(!host.is_null()); let host = CStr::from_ptr(host).to_str().expect("Bad encoding"); let connection = match servicepoint::Connection::open(host) { Err(_) => return null_mut(), @@ -45,59 +46,78 @@ pub unsafe extern "C" fn sp_connection_open( Box::into_raw(Box::new(SPConnection(connection))) } -/// Sends a `SPPacket` to the display using the `SPConnection`. +/// Sends a [SPPacket] to the display using the [SPConnection]. /// /// The passed `packet` gets consumed. /// /// returns: true in case of success /// +/// # Panics +/// +/// - when `connection` is NULL +/// - when `packet` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `connection` points to a valid instance of `SPConnection` -/// - `packet` points to a valid instance of `SPPacket` +/// - `connection` points to a valid instance of [SPConnection] +/// - `packet` points to a valid instance of [SPPacket] /// - `packet` is not used concurrently or after this call #[no_mangle] pub unsafe extern "C" fn sp_connection_send_packet( connection: *const SPConnection, packet: *mut SPPacket, ) -> bool { + assert!(!connection.is_null()); + assert!(!packet.is_null()); let packet = Box::from_raw(packet); (*connection).0.send((*packet).0).is_ok() } -/// Sends a `SPCommand` to the display using the `SPConnection`. +/// Sends a [SPCommand] to the display using the [SPConnection]. /// /// The passed `command` gets consumed. /// /// returns: true in case of success /// +/// # Panics +/// +/// - when `connection` is NULL +/// - when `command` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `connection` points to a valid instance of `SPConnection` -/// - `command` points to a valid instance of `SPPacket` +/// - `connection` points to a valid instance of [SPConnection] +/// - `command` points to a valid instance of [SPPacket] /// - `command` is not used concurrently or after this call #[no_mangle] pub unsafe extern "C" fn sp_connection_send_command( connection: *const SPConnection, command: *mut SPCommand, ) -> bool { + assert!(!connection.is_null()); + assert!(!command.is_null()); let command = (*Box::from_raw(command)).0; (*connection).0.send(command).is_ok() } -/// Closes and deallocates a `SPConnection`. +/// Closes and deallocates a [SPConnection]. +/// +/// # Panics +/// +/// - when `connection` is NULL /// /// # Safety /// /// The caller has to make sure that: /// -/// - `connection` points to a valid `SPConnection` +/// - `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: *mut SPConnection) { + assert!(!connection.is_null()); _ = Box::from_raw(connection); } diff --git a/crates/servicepoint_binding_c/src/cp437_grid.rs b/crates/servicepoint_binding_c/src/cp437_grid.rs index 781c345..b940ae4 100644 --- a/crates/servicepoint_binding_c/src/cp437_grid.rs +++ b/crates/servicepoint_binding_c/src/cp437_grid.rs @@ -1,7 +1,8 @@ -//! C functions for interacting with `SPCp437Grid`s +//! C functions for interacting with [SPCp437Grid]s //! //! prefix `sp_cp437_grid_` +use std::ptr::NonNull; use crate::SPByteSlice; use servicepoint::{DataRef, Grid}; @@ -25,9 +26,9 @@ impl Clone for SPCp437Grid { } } -/// Creates a new `SPCp437Grid` with the specified dimensions. +/// Creates a new [SPCp437Grid] with the specified dimensions. /// -/// returns: `SPCp437Grid` initialized to 0. +/// returns: [SPCp437Grid] initialized to 0. Will never return NULL. /// /// # Safety /// @@ -39,19 +40,21 @@ impl Clone for SPCp437Grid { pub unsafe extern "C" fn sp_cp437_grid_new( width: usize, height: usize, -) -> *mut SPCp437Grid { - Box::into_raw(Box::new(SPCp437Grid(servicepoint::Cp437Grid::new( - width, height, - )))) +) -> NonNull { + let result = Box::new(SPCp437Grid( + servicepoint::Cp437Grid::new(width, height), + )); + NonNull::from(Box::leak(result)) } -/// Loads a `SPCp437Grid` with the specified dimensions from the provided data. +/// Loads a [SPCp437Grid] with the specified dimensions from the provided data. /// /// Will never return NULL. /// /// # Panics /// -/// When the provided `data_length` is not sufficient for the `height` and `width` +/// - when `data` is NULL +/// - when the provided `data_length` does not match `height` and `width` /// /// # Safety /// @@ -67,43 +70,56 @@ pub unsafe extern "C" fn sp_cp437_grid_load( height: usize, data: *const u8, data_length: usize, -) -> *mut SPCp437Grid { +) -> NonNull { + assert!(data.is_null()); let data = std::slice::from_raw_parts(data, data_length); - Box::into_raw(Box::new(SPCp437Grid(servicepoint::Cp437Grid::load( - width, height, data, - )))) + let result = Box::new(SPCp437Grid( + servicepoint::Cp437Grid::load(width, height, data), + )); + NonNull::from(Box::leak(result)) } -/// Clones a `SPCp437Grid`. +/// Clones a [SPCp437Grid]. /// /// Will never return NULL. /// +/// # Panics +/// +/// - when `cp437_grid` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `cp437_grid` points to a valid `SPCp437Grid` +/// - `cp437_grid` points to a valid [SPCp437Grid] /// - `cp437_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_cp437_grid_free`. #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_clone( cp437_grid: *const SPCp437Grid, -) -> *mut SPCp437Grid { - Box::into_raw(Box::new((*cp437_grid).clone())) +) -> NonNull { + assert!(!cp437_grid.is_null()); + let result = Box::new((*cp437_grid).clone()); + NonNull::from(Box::leak(result)) } -/// Deallocates a `SPCp437Grid`. +/// Deallocates a [SPCp437Grid]. +/// +/// # Panics +/// +/// - when `cp437_grid` is NULL /// /// # Safety /// /// The caller has to make sure that: /// -/// - `cp437_grid` points to a valid `SPCp437Grid` +/// - `cp437_grid` points to a valid [SPCp437Grid] /// - `cp437_grid` is not used concurrently or after cp437_grid call -/// - `cp437_grid` was not passed to another consuming function, e.g. to create a `SPCommand` +/// - `cp437_grid` was not passed to another consuming function, e.g. to create a [SPCommand] #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) { + assert!(!cp437_grid.is_null()); _ = Box::from_raw(cp437_grid); } @@ -116,13 +132,14 @@ pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) { /// /// # Panics /// -/// When accessing `x` or `y` out of bounds. +/// - when `cp437_grid` is NULL +/// - when accessing `x` or `y` out of bounds /// /// # Safety /// /// The caller has to make sure that: /// -/// - `cp437_grid` points to a valid `SPCp437Grid` +/// - `cp437_grid` points to a valid [SPCp437Grid] /// - `cp437_grid` is not written to concurrently #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_get( @@ -130,10 +147,11 @@ pub unsafe extern "C" fn sp_cp437_grid_get( x: usize, y: usize, ) -> u8 { + assert!(!cp437_grid.is_null()); (*cp437_grid).0.get(x, y) } -/// Sets the value of the specified position in the `SPCp437Grid`. +/// Sets the value of the specified position in the [SPCp437Grid]. /// /// # Arguments /// @@ -145,13 +163,14 @@ pub unsafe extern "C" fn sp_cp437_grid_get( /// /// # Panics /// -/// When accessing `x` or `y` out of bounds. +/// - when `cp437_grid` is NULL +/// - when accessing `x` or `y` out of bounds /// /// # Safety /// /// The caller has to make sure that: /// -/// - `cp437_grid` points to a valid `SPBitVec` +/// - `cp437_grid` points to a valid [SPBitVec] /// - `cp437_grid` is not written to or read from concurrently #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_set( @@ -160,84 +179,104 @@ pub unsafe extern "C" fn sp_cp437_grid_set( y: usize, value: u8, ) { + assert!(!cp437_grid.is_null()); (*cp437_grid).0.set(x, y, value); } -/// Sets the value of all cells in the `SPCp437Grid`. +/// Sets the value of all cells in the [SPCp437Grid]. /// /// # Arguments /// /// - `cp437_grid`: instance to write to /// - `value`: the value to set all cells to /// +/// # Panics +/// +/// - when `cp437_grid` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `cp437_grid` points to a valid `SPCp437Grid` +/// - `cp437_grid` points to a valid [SPCp437Grid] /// - `cp437_grid` is not written to or read from concurrently #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_fill( cp437_grid: *mut SPCp437Grid, value: u8, ) { + assert!(!cp437_grid.is_null()); (*cp437_grid).0.fill(value); } -/// Gets the width of the `SPCp437Grid` instance. +/// Gets the width of the [SPCp437Grid] instance. /// /// # Arguments /// /// - `cp437_grid`: instance to read from /// +/// # Panics +/// +/// - when `cp437_grid` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `cp437_grid` points to a valid `SPCp437Grid` +/// - `cp437_grid` points to a valid [SPCp437Grid] #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_width( cp437_grid: *const SPCp437Grid, ) -> usize { + assert!(!cp437_grid.is_null()); (*cp437_grid).0.width() } -/// Gets the height of the `SPCp437Grid` instance. +/// Gets the height of the [SPCp437Grid] instance. /// /// # Arguments /// /// - `cp437_grid`: instance to read from /// +/// # Panics +/// +/// - when `cp437_grid` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `cp437_grid` points to a valid `SPCp437Grid` +/// - `cp437_grid` points to a valid [SPCp437Grid] #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_height( cp437_grid: *const SPCp437Grid, ) -> usize { + assert!(!cp437_grid.is_null()); (*cp437_grid).0.height() } -/// Gets an unsafe reference to the data of the `SPCp437Grid` instance. +/// Gets an unsafe reference to the data of the [SPCp437Grid] instance. /// /// Will never return NULL. /// +/// # Panics +/// +/// - when `cp437_grid` is NULL +/// /// ## Safety /// /// The caller has to make sure that: /// -/// - `cp437_grid` points to a valid `SPCp437Grid` -/// - 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 +/// - `cp437_grid` points to a valid [SPCp437Grid] +/// - 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 #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_unsafe_data_ref( cp437_grid: *mut SPCp437Grid, ) -> SPByteSlice { let data = (*cp437_grid).0.data_ref_mut(); SPByteSlice { - start: data.as_mut_ptr_range().start, + start: NonNull::new(data.as_mut_ptr_range().start).unwrap(), length: data.len(), } } diff --git a/crates/servicepoint_binding_c/src/lib.rs b/crates/servicepoint_binding_c/src/lib.rs index d6f839b..0e0ddd0 100644 --- a/crates/servicepoint_binding_c/src/lib.rs +++ b/crates/servicepoint_binding_c/src/lib.rs @@ -13,8 +13,8 @@ //! if (connection == NULL) //! return 1; //! -//! SPPixelGrid *pixels = sp_pixel_grid_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT); -//! sp_pixel_grid_fill(pixels, true); +//! SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT); +//! sp_bitmap_fill(pixels, true); //! //! SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed); //! while (sp_connection_send_command(connection, sp_command_clone(command))); @@ -25,7 +25,8 @@ //! } //! ``` -pub use crate::bit_vec::*; +pub use crate::bitvec::*; +pub use crate::bitmap::*; pub use crate::brightness_grid::*; pub use crate::byte_slice::*; pub use crate::command::*; @@ -33,9 +34,9 @@ pub use crate::connection::*; pub use crate::constants::*; pub use crate::cp437_grid::*; pub use crate::packet::*; -pub use crate::pixel_grid::*; -mod bit_vec; +mod bitvec; +mod bitmap; mod brightness_grid; mod byte_slice; mod command; @@ -43,4 +44,3 @@ mod connection; mod constants; mod cp437_grid; mod packet; -mod pixel_grid; diff --git a/crates/servicepoint_binding_c/src/packet.rs b/crates/servicepoint_binding_c/src/packet.rs index 5dc5820..e44c23f 100644 --- a/crates/servicepoint_binding_c/src/packet.rs +++ b/crates/servicepoint_binding_c/src/packet.rs @@ -1,53 +1,63 @@ -//! C functions for interacting with `SPPacket`s +//! C functions for interacting with [SPPacket]s //! //! prefix `sp_packet_` -use std::ptr::null_mut; +use std::ptr::{null_mut, NonNull}; use crate::SPCommand; /// The raw packet pub struct SPPacket(pub(crate) servicepoint::packet::Packet); -/// Turns a `SPCommand` into a `SPPacket`. -/// The `SPCommand` gets consumed. +/// Turns a [SPCommand] into a [SPPacket]. +/// The [SPCommand] gets consumed. /// /// Will never return NULL. /// +/// # Panics +/// +/// - when `command` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `SPCommand` points to a valid instance of `SPCommand` -/// - `SPCommand` is not used concurrently or after this call -/// - the returned `SPPacket` instance is freed in some way, either by using a consuming function or +/// - [SPCommand] points to a valid instance of [SPCommand] +/// - [SPCommand] is not used concurrently or after this call +/// - 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_from_command( command: *mut SPCommand, -) -> *mut SPPacket { +) -> NonNull { + assert!(!command.is_null()); let command = *Box::from_raw(command); - let packet = SPPacket(command.0.into()); - Box::into_raw(Box::new(packet)) + let result = Box::new(SPPacket(command.0.into())); + NonNull::from(Box::leak(result)) } -/// Tries to load a `SPPacket` from the passed array with the specified length. +/// Tries to load a [SPPacket] from the passed array with the specified length. /// /// returns: NULL in case of an error, pointer to the allocated packet otherwise /// +/// # Panics +/// +/// - when `data` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// /// - `data` points to a valid memory region of at least `length` bytes /// - `data` is not written to concurrently -/// - the returned `SPPacket` instance is freed in some way, either by using a consuming function or +/// - 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: *const u8, length: usize, ) -> *mut SPPacket { + assert!(!data.is_null()); let data = std::slice::from_raw_parts(data, length); match servicepoint::packet::Packet::try_from(data) { Err(_) => null_mut(), @@ -55,34 +65,45 @@ pub unsafe extern "C" fn sp_packet_try_load( } } -/// Clones a `SPPacket`. +/// Clones a [SPPacket]. /// /// Will never return NULL. /// +/// # Panics +/// +/// - when `packet` is NULL +/// /// # Safety /// /// The caller has to make sure that: /// -/// - `packet` points to a valid `SPPacket` +/// - `packet` points to a valid [SPPacket] /// - `packet` is not written to concurrently /// - the returned 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_clone( packet: *const SPPacket, -) -> *mut SPPacket { - Box::into_raw(Box::new(SPPacket((*packet).0.clone()))) +) -> NonNull { + assert!(!packet.is_null()); + let result = Box::new(SPPacket((*packet).0.clone())); + NonNull::from(Box::leak(result)) } -/// Deallocates a `SPPacket`. +/// Deallocates a [SPPacket]. +/// +/// # Panics +/// +/// - when `sp_packet_free` is NULL /// /// # Safety /// /// The caller has to make sure that: /// -/// - `packet` points to a valid `SPPacket` +/// - `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: *mut SPPacket) { + assert!(!packet.is_null()); _ = Box::from_raw(packet) } diff --git a/crates/servicepoint_binding_c/src/pixel_grid.rs b/crates/servicepoint_binding_c/src/pixel_grid.rs deleted file mode 100644 index 780c305..0000000 --- a/crates/servicepoint_binding_c/src/pixel_grid.rs +++ /dev/null @@ -1,248 +0,0 @@ -//! C functions for interacting with `SPPixelGrid`s -//! -//! prefix `sp_pixel_grid_` - -use servicepoint::{DataRef, Grid}; - -use crate::byte_slice::SPByteSlice; - -/// A grid of pixels. -/// -/// # Examples -/// -/// ```C -/// Cp437Grid grid = sp_pixel_grid_new(8, 3); -/// sp_pixel_grid_fill(grid, true); -/// sp_pixel_grid_set(grid, 0, 0, false); -/// sp_pixel_grid_free(grid); -/// ``` -pub struct SPPixelGrid(pub(crate) servicepoint::PixelGrid); - -/// Creates a new `SPPixelGrid` with the specified dimensions. -/// -/// # Arguments -/// -/// - `width`: size in pixels in x-direction -/// - `height`: size in pixels in y-direction -/// -/// returns: `SPPixelGrid` initialized to all pixels off. Will never return NULL. -/// -/// # Panics -/// -/// - when the width is not dividable by 8 -/// -/// # 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_pixel_grid_free`. -#[no_mangle] -pub unsafe extern "C" fn sp_pixel_grid_new( - width: usize, - height: usize, -) -> *mut SPPixelGrid { - Box::into_raw(Box::new(SPPixelGrid(servicepoint::PixelGrid::new( - width, height, - )))) -} - -/// Loads a `SPPixelGrid` with the specified dimensions from the provided data. -/// -/// # Arguments -/// -/// - `width`: size in pixels in x-direction -/// - `height`: size in pixels in y-direction -/// -/// returns: `SPPixelGrid` that contains a copy of the provided data. Will never return NULL. -/// -/// # Panics -/// -/// - when the dimensions and data size do not match exactly. -/// - when the width is not dividable by 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_pixel_grid_free`. -#[no_mangle] -pub unsafe extern "C" fn sp_pixel_grid_load( - width: usize, - height: usize, - data: *const u8, - data_length: usize, -) -> *mut SPPixelGrid { - let data = std::slice::from_raw_parts(data, data_length); - Box::into_raw(Box::new(SPPixelGrid(servicepoint::PixelGrid::load( - width, height, data, - )))) -} - -/// Clones a `SPPixelGrid`. -/// -/// Will never return NULL. -/// -/// # Safety -/// -/// The caller has to make sure that: -/// -/// - `pixel_grid` points to a valid `SPPixelGrid` -/// - `pixel_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_pixel_grid_free`. -#[no_mangle] -pub unsafe extern "C" fn sp_pixel_grid_clone( - pixel_grid: *const SPPixelGrid, -) -> *mut SPPixelGrid { - Box::into_raw(Box::new(SPPixelGrid((*pixel_grid).0.clone()))) -} - -/// Deallocates a `SPPixelGrid`. -/// -/// # Safety -/// -/// The caller has to make sure that: -/// -/// - `pixel_grid` points to a valid `SPPixelGrid` -/// - `pixel_grid` is not used concurrently or after pixel_grid call -/// - `pixel_grid` was not passed to another consuming function, e.g. to create a `SPCommand` -#[no_mangle] -pub unsafe extern "C" fn sp_pixel_grid_free(pixel_grid: *mut SPPixelGrid) { - _ = Box::from_raw(pixel_grid); -} - -/// Gets the current value at the specified position in the `SPPixelGrid`. -/// -/// # Arguments -/// -/// - `pixel_grid`: instance to read from -/// - `x` and `y`: position of the cell to read -/// -/// # Panics -/// -/// When accessing `x` or `y` out of bounds. -/// -/// # Safety -/// -/// The caller has to make sure that: -/// -/// - `pixel_grid` points to a valid `SPPixelGrid` -/// - `pixel_grid` is not written to concurrently -#[no_mangle] -pub unsafe extern "C" fn sp_pixel_grid_get( - pixel_grid: *const SPPixelGrid, - x: usize, - y: usize, -) -> bool { - (*pixel_grid).0.get(x, y) -} - -/// Sets the value of the specified position in the `SPPixelGrid`. -/// -/// # Arguments -/// -/// - `pixel_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 accessing `x` or `y` out of bounds. -/// -/// # Safety -/// -/// The caller has to make sure that: -/// -/// - `pixel_grid` points to a valid `SPPixelGrid` -/// - `pixel_grid` is not written to or read from concurrently -#[no_mangle] -pub unsafe extern "C" fn sp_pixel_grid_set( - pixel_grid: *mut SPPixelGrid, - x: usize, - y: usize, - value: bool, -) { - (*pixel_grid).0.set(x, y, value); -} - -/// Sets the state of all pixels in the `SPPixelGrid`. -/// -/// # Arguments -/// -/// - `pixel_grid`: instance to write to -/// - `value`: the value to set all pixels to -/// -/// # Safety -/// -/// The caller has to make sure that: -/// -/// - `pixel_grid` points to a valid `SPPixelGrid` -/// - `pixel_grid` is not written to or read from concurrently -#[no_mangle] -pub unsafe extern "C" fn sp_pixel_grid_fill( - pixel_grid: *mut SPPixelGrid, - value: bool, -) { - (*pixel_grid).0.fill(value); -} - -/// Gets the width in pixels of the `SPPixelGrid` instance. -/// -/// # Arguments -/// -/// - `pixel_grid`: instance to read from -/// -/// # Safety -/// -/// The caller has to make sure that: -/// -/// - `pixel_grid` points to a valid `SPPixelGrid` -#[no_mangle] -pub unsafe extern "C" fn sp_pixel_grid_width( - pixel_grid: *const SPPixelGrid, -) -> usize { - (*pixel_grid).0.width() -} - -/// Gets the height in pixels of the `SPPixelGrid` instance. -/// -/// # Arguments -/// -/// - `pixel_grid`: instance to read from -/// -/// # Safety -/// -/// The caller has to make sure that: -/// -/// - `pixel_grid` points to a valid `SPPixelGrid` -#[no_mangle] -pub unsafe extern "C" fn sp_pixel_grid_height( - pixel_grid: *const SPPixelGrid, -) -> usize { - (*pixel_grid).0.height() -} - -/// Gets an unsafe reference to the data of the `SPPixelGrid` instance. -/// -/// ## Safety -/// -/// The caller has to make sure that: -/// -/// - `pixel_grid` points to a valid `SPPixelGrid` -/// - the returned memory range is never accessed after the passed `SPPixelGrid` has been freed -/// - the returned memory range is never accessed concurrently, either via the `SPPixelGrid` or directly -#[no_mangle] -pub unsafe extern "C" fn sp_pixel_grid_unsafe_data_ref( - pixel_grid: *mut SPPixelGrid, -) -> SPByteSlice { - let data = (*pixel_grid).0.data_ref_mut(); - SPByteSlice { - start: data.as_mut_ptr_range().start, - length: data.len(), - } -} diff --git a/crates/servicepoint_binding_cs/Cargo.toml b/crates/servicepoint_binding_cs/Cargo.toml index 8333a21..caca7b9 100644 --- a/crates/servicepoint_binding_cs/Cargo.toml +++ b/crates/servicepoint_binding_cs/Cargo.toml @@ -13,8 +13,8 @@ test = false csbindgen = "1.9.3" [dependencies] -servicepoint_binding_c = { version = "0.9.1", path = "../servicepoint_binding_c" } -servicepoint = { version = "0.9.1", path = "../servicepoint" } +servicepoint_binding_c = { version = "0.10.0", path = "../servicepoint_binding_c" } +servicepoint = { version = "0.10.0", path = "../servicepoint" } [lints] workspace = true diff --git a/crates/servicepoint_binding_cs/README.md b/crates/servicepoint_binding_cs/README.md index 0f5ee3d..bd2107a 100644 --- a/crates/servicepoint_binding_cs/README.md +++ b/crates/servicepoint_binding_cs/README.md @@ -11,7 +11,7 @@ using ServicePoint; // using statement calls Dispose() on scope exit, which frees unmanaged instances using var connection = Connection.Open("127.0.0.1:2342"); -using var pixels = PixelGrid.New(Constants.PixelWidth, Constants.PixelHeight); +using var pixels = Bitmap.New(Constants.PixelWidth, Constants.PixelHeight); while (true) { diff --git a/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs b/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs index d23b2b9..c8bb0a2 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs @@ -14,36 +14,265 @@ namespace ServicePoint.BindGen { const string __DllName = "servicepoint_binding_c"; + public const byte SP_BRIGHTNESS_MIN = 0; + public const byte SP_BRIGHTNESS_MAX = 11; + public const byte SP_BRIGHTNESS_LEVELS = 12; public const nuint SP_TILE_SIZE = 8; public const nuint SP_TILE_WIDTH = 56; public const nuint SP_TILE_HEIGHT = 20; /// - /// Creates a new `SPBitVec` instance. + /// Creates a new [SPBitmap] with the specified dimensions. /// /// # Arguments /// - /// - `size`: size in bits. + /// - `width`: size in pixels in x-direction + /// - `height`: size in pixels in y-direction /// - /// returns: `SPBitVec` with all bits set to false. Will never return NULL. + /// returns: [SPBitmap] initialized to all pixels off. Will never return NULL. /// /// # Panics /// - /// When `size` is not divisible by 8. + /// - when the width is not dividable by 8 /// /// # 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_bit_vec_free`. + /// by explicitly calling `sp_bitmap_free`. /// - [DllImport(__DllName, EntryPoint = "sp_bit_vec_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern BitVec* sp_bit_vec_new(nuint size); + [DllImport(__DllName, EntryPoint = "sp_bitmap_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern Bitmap* sp_bitmap_new(nuint width, nuint height); /// - /// Interpret the data as a series of bits and load then into a new `SPBitVec` instance. + /// Loads a [SPBitmap] with the specified dimensions from the provided data. + /// + /// # Arguments + /// + /// - `width`: size in pixels in x-direction + /// - `height`: size in pixels in y-direction + /// + /// returns: [SPBitmap] that contains a copy of the provided data. Will never return NULL. + /// + /// # Panics + /// + /// - when `data` is NULL + /// - when the dimensions and data size do not match exactly. + /// - when the width is not dividable by 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_bitmap_free`. + /// + [DllImport(__DllName, EntryPoint = "sp_bitmap_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern Bitmap* sp_bitmap_load(nuint width, nuint height, byte* data, nuint data_length); + + /// + /// Clones a [SPBitmap]. + /// + /// Will never return NULL. + /// + /// # Panics + /// + /// - when `bitmap` is NULL + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bitmap` points to a valid [SPBitmap] + /// - `bitmap` is not written to concurrently + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_bitmap_free`. + /// + [DllImport(__DllName, EntryPoint = "sp_bitmap_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern Bitmap* sp_bitmap_clone(Bitmap* bitmap); + + /// + /// Deallocates a [SPBitmap]. + /// + /// # Panics + /// + /// - when `bitmap` is NULL + /// + /// # Safety + /// + /// 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] + /// + [DllImport(__DllName, EntryPoint = "sp_bitmap_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_bitmap_free(Bitmap* bitmap); + + /// + /// Gets the current value at the specified position in the [SPBitmap]. + /// + /// # Arguments + /// + /// - `bitmap`: instance to read from + /// - `x` and `y`: position of the cell to read + /// + /// # Panics + /// + /// - when `bitmap` is NULL + /// - when accessing `x` or `y` out of bounds + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bitmap` points to a valid [SPBitmap] + /// - `bitmap` is not written to concurrently + /// + [DllImport(__DllName, EntryPoint = "sp_bitmap_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [return: MarshalAs(UnmanagedType.U1)] + public static extern bool sp_bitmap_get(Bitmap* bitmap, nuint x, nuint y); + + /// + /// Sets the value of the specified position in the [SPBitmap]. + /// + /// # Arguments + /// + /// - `bitmap`: 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 `bitmap` is NULL + /// - when accessing `x` or `y` out of bounds + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bitmap` points to a valid [SPBitmap] + /// - `bitmap` is not written to or read from concurrently + /// + [DllImport(__DllName, EntryPoint = "sp_bitmap_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_bitmap_set(Bitmap* bitmap, nuint x, nuint y, [MarshalAs(UnmanagedType.U1)] bool value); + + /// + /// Sets the state of all pixels in the [SPBitmap]. + /// + /// # Arguments + /// + /// - `bitmap`: instance to write to + /// - `value`: the value to set all pixels to + /// + /// # Panics + /// + /// - when `bitmap` is NULL + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bitmap` points to a valid [SPBitmap] + /// - `bitmap` is not written to or read from concurrently + /// + [DllImport(__DllName, EntryPoint = "sp_bitmap_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_bitmap_fill(Bitmap* bitmap, [MarshalAs(UnmanagedType.U1)] bool value); + + /// + /// Gets the width in pixels of the [SPBitmap] instance. + /// + /// # Arguments + /// + /// - `bitmap`: instance to read from + /// + /// # Panics + /// + /// - when `bitmap` is NULL + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bitmap` points to a valid [SPBitmap] + /// + [DllImport(__DllName, EntryPoint = "sp_bitmap_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern nuint sp_bitmap_width(Bitmap* bitmap); + + /// + /// Gets the height in pixels of the [SPBitmap] instance. + /// + /// # Arguments + /// + /// - `bitmap`: instance to read from + /// + /// # Panics + /// + /// - when `bitmap` is NULL + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bitmap` points to a valid [SPBitmap] + /// + [DllImport(__DllName, EntryPoint = "sp_bitmap_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern nuint sp_bitmap_height(Bitmap* bitmap); + + /// + /// Gets an unsafe reference to the data of the [SPBitmap] instance. + /// + /// # Panics + /// + /// - when `bitmap` is NULL + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bitmap` points to a valid [SPBitmap] + /// - 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 + /// + [DllImport(__DllName, EntryPoint = "sp_bitmap_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern ByteSlice sp_bitmap_unsafe_data_ref(Bitmap* bitmap); + + /// + /// Creates a new [SPBitVec] instance. + /// + /// # Arguments + /// + /// - `size`: size in bits. + /// + /// returns: [SPBitVec] with all bits set to false. Will never return NULL. + /// + /// # Panics + /// + /// - when `size` is not divisible by 8. + /// + /// # 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_bitvec_free`. + /// + [DllImport(__DllName, EntryPoint = "sp_bitvec_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern BitVec* sp_bitvec_new(nuint size); + + /// + /// Interpret the data as a series of bits and load then into a new [SPBitVec] instance. + /// + /// returns: [SPBitVec] instance containing data. Will never return NULL. + /// + /// # Panics + /// + /// - when `data` is NULL /// /// # Safety /// @@ -52,42 +281,52 @@ namespace ServicePoint.BindGen /// - `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_bit_vec_free`. + /// by explicitly calling `sp_bitvec_free`. /// - [DllImport(__DllName, EntryPoint = "sp_bit_vec_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern BitVec* sp_bit_vec_load(byte* data, nuint data_length); + [DllImport(__DllName, EntryPoint = "sp_bitvec_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern BitVec* sp_bitvec_load(byte* data, nuint data_length); /// - /// Clones a `SPBitVec`. + /// Clones a [SPBitVec]. + /// + /// returns: new [SPBitVec] instance. Will never return NULL. + /// + /// # Panics + /// + /// - when `bit_vec` is NULL /// /// # Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` points to a valid [SPBitVec] /// - `bit_vec` is not written to concurrently /// - the returned instance is freed in some way, either by using a consuming function or - /// by explicitly calling `sp_bit_vec_free`. + /// by explicitly calling `sp_bitvec_free`. /// - [DllImport(__DllName, EntryPoint = "sp_bit_vec_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern BitVec* sp_bit_vec_clone(BitVec* bit_vec); + [DllImport(__DllName, EntryPoint = "sp_bitvec_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern BitVec* sp_bitvec_clone(BitVec* bit_vec); /// - /// Deallocates a `SPBitVec`. + /// Deallocates a [SPBitVec]. + /// + /// # Panics + /// + /// - when `but_vec` is NULL /// /// # Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` points to a valid [SPBitVec] /// - `bit_vec` is not used concurrently or after this call - /// - `bit_vec` was not passed to another consuming function, e.g. to create a `SPCommand` + /// - `bit_vec` was not passed to another consuming function, e.g. to create a [SPCommand] /// - [DllImport(__DllName, EntryPoint = "sp_bit_vec_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_bit_vec_free(BitVec* bit_vec); + [DllImport(__DllName, EntryPoint = "sp_bitvec_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_bitvec_free(BitVec* bit_vec); /// - /// Gets the value of a bit from the `SPBitVec`. + /// Gets the value of a bit from the [SPBitVec]. /// /// # Arguments /// @@ -98,21 +337,22 @@ namespace ServicePoint.BindGen /// /// # Panics /// - /// When accessing `index` out of bounds. + /// - when `bit_vec` is NULL + /// - when accessing `index` out of bounds /// /// # Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` points to a valid [SPBitVec] /// - `bit_vec` is not written to concurrently /// - [DllImport(__DllName, EntryPoint = "sp_bit_vec_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [DllImport(__DllName, EntryPoint = "sp_bitvec_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.U1)] - public static extern bool sp_bit_vec_get(BitVec* bit_vec, nuint index); + public static extern bool sp_bitvec_get(BitVec* bit_vec, nuint index); /// - /// Sets the value of a bit in the `SPBitVec`. + /// Sets the value of a bit in the [SPBitVec]. /// /// # Arguments /// @@ -120,55 +360,62 @@ namespace ServicePoint.BindGen /// - `index`: the bit index to edit /// - `value`: the value to set the bit to /// - /// returns: old value of the bit - /// /// # Panics /// - /// When accessing `index` out of bounds. + /// - when `bit_vec` is NULL + /// - when accessing `index` out of bounds /// /// # Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` points to a valid [SPBitVec] /// - `bit_vec` is not written to or read from concurrently /// - [DllImport(__DllName, EntryPoint = "sp_bit_vec_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_bit_vec_set(BitVec* bit_vec, nuint index, [MarshalAs(UnmanagedType.U1)] bool value); + [DllImport(__DllName, EntryPoint = "sp_bitvec_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_bitvec_set(BitVec* bit_vec, nuint index, [MarshalAs(UnmanagedType.U1)] bool value); /// - /// Sets the value of all bits in the `SPBitVec`. + /// Sets the value of all bits in the [SPBitVec]. /// /// # Arguments /// /// - `bit_vec`: instance to write to /// - `value`: the value to set all bits to /// + /// # Panics + /// + /// - when `bit_vec` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` points to a valid [SPBitVec] /// - `bit_vec` is not written to or read from concurrently /// - [DllImport(__DllName, EntryPoint = "sp_bit_vec_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_bit_vec_fill(BitVec* bit_vec, [MarshalAs(UnmanagedType.U1)] bool value); + [DllImport(__DllName, EntryPoint = "sp_bitvec_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_bitvec_fill(BitVec* bit_vec, [MarshalAs(UnmanagedType.U1)] bool value); /// - /// Gets the length of the `SPBitVec` in bits. + /// Gets the length of the [SPBitVec] in bits. /// /// # Arguments /// /// - `bit_vec`: instance to write to /// + /// # Panics + /// + /// - when `bit_vec` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` points to a valid [SPBitVec] /// - [DllImport(__DllName, EntryPoint = "sp_bit_vec_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern nuint sp_bit_vec_len(BitVec* bit_vec); + [DllImport(__DllName, EntryPoint = "sp_bitvec_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern nuint sp_bitvec_len(BitVec* bit_vec); /// /// Returns true if length is 0. @@ -177,38 +424,46 @@ namespace ServicePoint.BindGen /// /// - `bit_vec`: instance to write to /// + /// # Panics + /// + /// - when `bit_vec` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` points to a valid [SPBitVec] /// - [DllImport(__DllName, EntryPoint = "sp_bit_vec_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [DllImport(__DllName, EntryPoint = "sp_bitvec_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.U1)] - public static extern bool sp_bit_vec_is_empty(BitVec* bit_vec); + public static extern bool sp_bitvec_is_empty(BitVec* bit_vec); /// - /// Gets an unsafe reference to the data of the `SPBitVec` instance. + /// Gets an unsafe reference to the data of the [SPBitVec] instance. /// /// # Arguments /// /// - `bit_vec`: instance to write to /// + /// # Panics + /// + /// - when `bit_vec` is NULL + /// /// ## Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid `SPBitVec` - /// - 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 + /// - `bit_vec` points to a valid [SPBitVec] + /// - 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 /// - [DllImport(__DllName, EntryPoint = "sp_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern ByteSlice sp_bit_vec_unsafe_data_ref(BitVec* bit_vec); + [DllImport(__DllName, EntryPoint = "sp_bitvec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern ByteSlice sp_bitvec_unsafe_data_ref(BitVec* bit_vec); /// - /// Creates a new `SPBrightnessGrid` with the specified dimensions. + /// Creates a new [SPBrightnessGrid] with the specified dimensions. /// - /// returns: `SPBrightnessGrid` initialized to 0. Will never return NULL. + /// returns: [SPBrightnessGrid] initialized to 0. Will never return NULL. /// /// # Safety /// @@ -221,11 +476,14 @@ namespace ServicePoint.BindGen public static extern BrightnessGrid* sp_brightness_grid_new(nuint width, nuint height); /// - /// Loads a `SPBrightnessGrid` with the specified dimensions from the provided data. + /// Loads a [SPBrightnessGrid] with the specified dimensions from the provided data. + /// + /// returns: new [SPBrightnessGrid] instance. Will never return NULL. /// /// # Panics /// - /// When the provided `data_length` is not sufficient for the `height` and `width` + /// - when `data` is NULL + /// - when the provided `data_length` does not match `height` and `width` /// /// # Safety /// @@ -240,17 +498,23 @@ namespace ServicePoint.BindGen public static extern BrightnessGrid* sp_brightness_grid_load(nuint width, nuint height, byte* data, nuint data_length); /// - /// Clones a `SPBrightnessGrid`. + /// Clones a [SPBrightnessGrid]. /// /// # Arguments /// /// - `brightness_grid`: instance to read from /// + /// returns: new [SPBrightnessGrid] instance. Will never return NULL. + /// + /// # Panics + /// + /// - when `brightness_grid` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// - `brightness_grid` points to a valid [SPBrightnessGrid] /// - `brightness_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_brightness_grid_free`. @@ -259,19 +523,23 @@ namespace ServicePoint.BindGen public static extern BrightnessGrid* sp_brightness_grid_clone(BrightnessGrid* brightness_grid); /// - /// Deallocates a `SPBrightnessGrid`. + /// Deallocates a [SPBrightnessGrid]. /// /// # Arguments /// /// - `brightness_grid`: instance to read from /// + /// # Panics + /// + /// - when `brightness_grid` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// - `brightness_grid` points to a valid [SPBrightnessGrid] /// - `brightness_grid` is not used concurrently or after this call - /// - `brightness_grid` was not passed to another consuming function, e.g. to create a `SPCommand` + /// - `brightness_grid` was not passed to another consuming function, e.g. to create a [SPCommand] /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_brightness_grid_free(BrightnessGrid* brightness_grid); @@ -284,22 +552,25 @@ namespace ServicePoint.BindGen /// - `brightness_grid`: instance to read from /// - `x` and `y`: position of the cell to read /// + /// returns: value at position + /// /// # Panics /// - /// When accessing `x` or `y` out of bounds. + /// - when `brightness_grid` is NULL + /// - When accessing `x` or `y` out of bounds. /// /// # Safety /// /// The caller has to make sure that: /// - /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// - `brightness_grid` points to a valid [SPBrightnessGrid] /// - `brightness_grid` is not written to concurrently /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern byte sp_brightness_grid_get(BrightnessGrid* brightness_grid, nuint x, nuint y); /// - /// Sets the value of the specified position in the `SPBrightnessGrid`. + /// Sets the value of the specified position in the [SPBrightnessGrid]. /// /// # Arguments /// @@ -311,6 +582,7 @@ namespace ServicePoint.BindGen /// /// # Panics /// + /// - when `brightness_grid` is NULL /// - When accessing `x` or `y` out of bounds. /// - When providing an invalid brightness value /// @@ -318,14 +590,14 @@ namespace ServicePoint.BindGen /// /// The caller has to make sure that: /// - /// - `brightness_grid` points to a valid `SPBitVec` + /// - `brightness_grid` points to a valid [SPBitVec] /// - `brightness_grid` is not written to or read from concurrently /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_brightness_grid_set(BrightnessGrid* brightness_grid, nuint x, nuint y, byte value); /// - /// Sets the value of all cells in the `SPBrightnessGrid`. + /// Sets the value of all cells in the [SPBrightnessGrid]. /// /// # Arguments /// @@ -334,98 +606,127 @@ namespace ServicePoint.BindGen /// /// # Panics /// + /// - when `brightness_grid` is NULL /// - When providing an invalid brightness value /// /// # Safety /// /// The caller has to make sure that: /// - /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// - `brightness_grid` points to a valid [SPBrightnessGrid] /// - `brightness_grid` is not written to or read from concurrently /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_brightness_grid_fill(BrightnessGrid* brightness_grid, byte value); /// - /// Gets the width of the `SPBrightnessGrid` instance. + /// Gets the width of the [SPBrightnessGrid] instance. /// /// # Arguments /// /// - `brightness_grid`: instance to read from /// + /// returns: width + /// + /// # Panics + /// + /// - when `brightness_grid` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// - `brightness_grid` points to a valid [SPBrightnessGrid] /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern nuint sp_brightness_grid_width(BrightnessGrid* brightness_grid); /// - /// Gets the height of the `SPBrightnessGrid` instance. + /// Gets the height of the [SPBrightnessGrid] instance. /// /// # Arguments /// /// - `brightness_grid`: instance to read from /// + /// returns: height + /// + /// # Panics + /// + /// - when `brightness_grid` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// - `brightness_grid` points to a valid [SPBrightnessGrid] /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern nuint sp_brightness_grid_height(BrightnessGrid* brightness_grid); /// - /// Gets an unsafe reference to the data of the `SPBrightnessGrid` instance. + /// Gets an unsafe reference to the data of the [SPBrightnessGrid] instance. /// /// # Arguments /// /// - `brightness_grid`: instance to read from /// - /// ## Safety + /// returns: slice of bytes underlying the `brightness_grid`. /// - /// The caller has to make sure that: + /// # Panics /// - /// - `brightness_grid` points to a valid `SPBrightnessGrid` - /// - 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 - /// - [DllImport(__DllName, EntryPoint = "sp_brightness_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern ByteSlice sp_brightness_grid_unsafe_data_ref(BrightnessGrid* brightness_grid); - - /// - /// Tries to turn a `SPPacket` into a `SPCommand`. - /// - /// The packet is deallocated in the process. - /// - /// Returns: pointer to new `SPCommand` instance or NULL + /// - when `brightness_grid` is NULL /// /// # Safety /// /// The caller has to make sure that: /// - /// - `SPPacket` points to a valid instance of `SPPacket` - /// - `SPPacket` is not used concurrently or after this call + /// - `brightness_grid` points to a valid [SPBrightnessGrid] + /// - 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 + /// + [DllImport(__DllName, EntryPoint = "sp_brightness_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern ByteSlice sp_brightness_grid_unsafe_data_ref(BrightnessGrid* brightness_grid); + + /// + /// Tries to turn a [SPPacket] into a [SPCommand]. + /// + /// The packet is deallocated in the process. + /// + /// Returns: pointer to new [SPCommand] instance or NULL if parsing failed. + /// + /// # Panics + /// + /// - when `packet` is NULL + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - [SPPacket] points to a valid instance of [SPPacket] + /// - [SPPacket] is not used concurrently or after this call /// - the result is checked for NULL - /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern Command* sp_command_try_from_packet(Packet* packet); /// - /// Clones a `SPCommand` instance. + /// Clones a [SPCommand] instance. + /// + /// returns: new [SPCommand] instance. Will never return NULL. + /// + /// # Panics + /// + /// - when `command` is NULL /// /// # Safety /// /// The caller has to make sure that: /// - /// - `command` points to a valid instance of `SPCommand` + /// - `command` points to a valid instance of [SPCommand] /// - `command` is not written to concurrently - /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -436,7 +737,7 @@ namespace ServicePoint.BindGen /// /// Does not affect brightness. /// - /// Returns: a new `Command::Clear` instance. Will never return NULL. + /// Returns: a new [Command::Clear] instance. Will never return NULL. /// /// # Examples /// @@ -448,7 +749,7 @@ namespace ServicePoint.BindGen /// /// The caller has to make sure that: /// - /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_clear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -459,13 +760,13 @@ namespace ServicePoint.BindGen /// /// Please do not send this in your normal program flow. /// - /// Returns: a new `Command::HardReset` instance. Will never return NULL. + /// Returns: a new [Command::HardReset] instance. Will never return NULL. /// /// # Safety /// /// The caller has to make sure that: /// - /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_hard_reset", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -480,7 +781,7 @@ namespace ServicePoint.BindGen /// /// The caller has to make sure that: /// - /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -489,7 +790,7 @@ namespace ServicePoint.BindGen /// /// Set the brightness of all tiles to the same value. /// - /// Returns: a new `Command::Brightness` instance. Will never return NULL. + /// Returns: a new [Command::Brightness] instance. Will never return NULL. /// /// # Panics /// @@ -499,7 +800,7 @@ namespace ServicePoint.BindGen /// /// The caller has to make sure that: /// - /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -508,17 +809,21 @@ namespace ServicePoint.BindGen /// /// Set the brightness of individual tiles in a rectangular area of the display. /// - /// The passed `SPBrightnessGrid` gets consumed. + /// The passed [SPBrightnessGrid] gets consumed. /// - /// Returns: a new `Command::CharBrightness` instance. Will never return NULL. + /// Returns: a new [Command::CharBrightness] 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 `SPBrightnessGrid` + /// - `grid` points to a valid instance of [SPBrightnessGrid] /// - `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 + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_char_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -530,20 +835,25 @@ namespace ServicePoint.BindGen /// The screen will continuously overwrite more pixel data without regarding the offset, meaning /// once the starting row is full, overwriting will continue on column 0. /// - /// The contained `SPBitVec` is always uncompressed. + /// The contained [SPBitVec] is always uncompressed. /// - /// The passed `SPBitVec` gets consumed. + /// The passed [SPBitVec] gets consumed. /// - /// Returns: a new `Command::BitmapLinear` instance. Will never return NULL. + /// Returns: a new [Command::BitmapLinear] instance. Will never return NULL. + /// + /// # Panics + /// + /// - when `bit_vec` is null + /// - when `compression_code` is not a valid value /// /// # Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid instance of `SPBitVec` + /// - `bit_vec` points to a valid instance of [SPBitVec] /// - `bit_vec` is not used concurrently or after this call /// - `compression` matches one of the allowed enum values - /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -555,20 +865,25 @@ namespace ServicePoint.BindGen /// The screen will continuously overwrite more pixel data without regarding the offset, meaning /// once the starting row is full, overwriting will continue on column 0. /// - /// The contained `SPBitVec` is always uncompressed. + /// The contained [SPBitVec] is always uncompressed. /// - /// The passed `SPBitVec` gets consumed. + /// The passed [SPBitVec] gets consumed. /// - /// Returns: a new `Command::BitmapLinearAnd` instance. Will never return NULL. + /// Returns: a new [Command::BitmapLinearAnd] instance. Will never return NULL. + /// + /// # Panics + /// + /// - when `bit_vec` is null + /// - when `compression_code` is not a valid value /// /// # Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid instance of `SPBitVec` + /// - `bit_vec` points to a valid instance of [SPBitVec] /// - `bit_vec` is not used concurrently or after this call /// - `compression` matches one of the allowed enum values - /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_and", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -580,20 +895,25 @@ namespace ServicePoint.BindGen /// The screen will continuously overwrite more pixel data without regarding the offset, meaning /// once the starting row is full, overwriting will continue on column 0. /// - /// The contained `SPBitVec` is always uncompressed. + /// The contained [SPBitVec] is always uncompressed. /// - /// The passed `SPBitVec` gets consumed. + /// The passed [SPBitVec] gets consumed. /// - /// Returns: a new `Command::BitmapLinearOr` instance. Will never return NULL. + /// Returns: a new [Command::BitmapLinearOr] instance. Will never return NULL. + /// + /// # Panics + /// + /// - when `bit_vec` is null + /// - when `compression_code` is not a valid value /// /// # Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid instance of `SPBitVec` + /// - `bit_vec` points to a valid instance of [SPBitVec] /// - `bit_vec` is not used concurrently or after this call /// - `compression` matches one of the allowed enum values - /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_or", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -605,20 +925,25 @@ namespace ServicePoint.BindGen /// The screen will continuously overwrite more pixel data without regarding the offset, meaning /// once the starting row is full, overwriting will continue on column 0. /// - /// The contained `SPBitVec` is always uncompressed. + /// The contained [SPBitVec] is always uncompressed. /// - /// The passed `SPBitVec` gets consumed. + /// The passed [SPBitVec] gets consumed. /// - /// Returns: a new `Command::BitmapLinearXor` instance. Will never return NULL. + /// Returns: a new [Command::BitmapLinearXor] instance. Will never return NULL. + /// + /// # Panics + /// + /// - when `bit_vec` is null + /// - when `compression_code` is not a valid value /// /// # Safety /// /// The caller has to make sure that: /// - /// - `bit_vec` points to a valid instance of `SPBitVec` + /// - `bit_vec` points to a valid instance of [SPBitVec] /// - `bit_vec` is not used concurrently or after this call /// - `compression` matches one of the allowed enum values - /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_xor", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -627,22 +952,21 @@ namespace ServicePoint.BindGen /// /// Show text on the screen. /// - /// <div class="warning"> - /// The library does not currently convert between UTF-8 and CP-437. - /// Because Rust expects UTF-8 strings, it might be necessary to only send ASCII for now. - /// </div> + /// The passed [SPCp437Grid] gets consumed. /// - /// The passed `SPCp437Grid` gets consumed./// + /// Returns: a new [Command::Cp437Data] instance. Will never return NULL. /// - /// Returns: a new `Command::Cp437Data` 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 `SPCp437Grid` + /// - `grid` points to a valid instance of [SPCp437Grid] /// - `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 + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_cp437_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -651,25 +975,30 @@ namespace ServicePoint.BindGen /// /// Sets a window of pixels to the specified values. /// - /// The passed `SPPixelGrid` gets consumed. + /// The passed [SPBitmap] gets consumed. /// - /// Returns: a new `Command::BitmapLinearWin` instance. Will never return NULL. + /// Returns: a new [Command::BitmapLinearWin] instance. Will never return NULL. + /// + /// # Panics + /// + /// - when `bitmap` is null + /// - when `compression_code` is not a valid value /// /// # Safety /// /// The caller has to make sure that: /// - /// - `pixel_grid` points to a valid instance of `SPPixelGrid` - /// - `pixel_grid` is not used concurrently or after this call + /// - `bitmap` points to a valid instance of [SPBitmap] + /// - `bitmap` is not used concurrently or after this call /// - `compression` matches one of the allowed enum values - /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_command_free`. /// [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern Command* sp_command_bitmap_linear_win(nuint x, nuint y, PixelGrid* pixel_grid, CompressionCode compression_code); + public static extern Command* sp_command_bitmap_linear_win(nuint x, nuint y, Bitmap* bitmap, CompressionCode compression_code); /// - /// Deallocates a `SPCommand`. + /// Deallocates a [SPCommand]. /// /// # Examples /// @@ -678,25 +1007,29 @@ namespace ServicePoint.BindGen /// sp_command_free(c); /// ``` /// + /// # Panics + /// + /// - when `command` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `command` points to a valid `SPCommand` + /// - `command` points to a valid [SPCommand] /// - `command` is not used concurrently or after this call - /// - `command` was not passed to another consuming function, e.g. to create a `SPPacket` + /// - `command` was not passed to another consuming function, e.g. to create a [SPPacket] /// [DllImport(__DllName, EntryPoint = "sp_command_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_command_free(Command* command); /// - /// Creates a new instance of `SPConnection`. + /// Creates a new instance of [SPConnection]. /// /// returns: NULL if connection fails, or connected instance /// /// # Panics /// - /// Bad string encoding + /// - when `host` is null or an invalid host /// /// # Safety /// @@ -709,18 +1042,23 @@ namespace ServicePoint.BindGen public static extern Connection* sp_connection_open(byte* host); /// - /// Sends a `SPPacket` to the display using the `SPConnection`. + /// Sends a [SPPacket] to the display using the [SPConnection]. /// /// The passed `packet` gets consumed. /// /// returns: true in case of success /// + /// # Panics + /// + /// - when `connection` is NULL + /// - when `packet` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `connection` points to a valid instance of `SPConnection` - /// - `packet` points to a valid instance of `SPPacket` + /// - `connection` points to a valid instance of [SPConnection] + /// - `packet` points to a valid instance of [SPPacket] /// - `packet` is not used concurrently or after this call /// [DllImport(__DllName, EntryPoint = "sp_connection_send_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -728,18 +1066,23 @@ namespace ServicePoint.BindGen public static extern bool sp_connection_send_packet(Connection* connection, Packet* packet); /// - /// Sends a `SPCommand` to the display using the `SPConnection`. + /// Sends a [SPCommand] to the display using the [SPConnection]. /// /// The passed `command` gets consumed. /// /// returns: true in case of success /// + /// # Panics + /// + /// - when `connection` is NULL + /// - when `command` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `connection` points to a valid instance of `SPConnection` - /// - `command` points to a valid instance of `SPPacket` + /// - `connection` points to a valid instance of [SPConnection] + /// - `command` points to a valid instance of [SPPacket] /// - `command` is not used concurrently or after this call /// [DllImport(__DllName, EntryPoint = "sp_connection_send_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -747,22 +1090,26 @@ namespace ServicePoint.BindGen public static extern bool sp_connection_send_command(Connection* connection, Command* command); /// - /// Closes and deallocates a `SPConnection`. + /// Closes and deallocates a [SPConnection]. + /// + /// # Panics + /// + /// - when `connection` is NULL /// /// # Safety /// /// The caller has to make sure that: /// - /// - `connection` points to a valid `SPConnection` + /// - `connection` points to a valid [SPConnection] /// - `connection` is not used concurrently or after this call /// [DllImport(__DllName, EntryPoint = "sp_connection_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_connection_free(Connection* connection); /// - /// Creates a new `SPCp437Grid` with the specified dimensions. + /// Creates a new [SPCp437Grid] with the specified dimensions. /// - /// returns: `SPCp437Grid` initialized to 0. + /// returns: [SPCp437Grid] initialized to 0. Will never return NULL. /// /// # Safety /// @@ -775,13 +1122,14 @@ namespace ServicePoint.BindGen public static extern Cp437Grid* sp_cp437_grid_new(nuint width, nuint height); /// - /// Loads a `SPCp437Grid` with the specified dimensions from the provided data. + /// Loads a [SPCp437Grid] with the specified dimensions from the provided data. /// /// Will never return NULL. /// /// # Panics /// - /// When the provided `data_length` is not sufficient for the `height` and `width` + /// - when `data` is NULL + /// - when the provided `data_length` does not match `height` and `width` /// /// # Safety /// @@ -796,15 +1144,19 @@ namespace ServicePoint.BindGen public static extern Cp437Grid* sp_cp437_grid_load(nuint width, nuint height, byte* data, nuint data_length); /// - /// Clones a `SPCp437Grid`. + /// Clones a [SPCp437Grid]. /// /// Will never return NULL. /// + /// # Panics + /// + /// - when `cp437_grid` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `cp437_grid` points to a valid `SPCp437Grid` + /// - `cp437_grid` points to a valid [SPCp437Grid] /// - `cp437_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_cp437_grid_free`. @@ -813,15 +1165,19 @@ namespace ServicePoint.BindGen public static extern Cp437Grid* sp_cp437_grid_clone(Cp437Grid* cp437_grid); /// - /// Deallocates a `SPCp437Grid`. + /// Deallocates a [SPCp437Grid]. + /// + /// # Panics + /// + /// - when `cp437_grid` is NULL /// /// # Safety /// /// The caller has to make sure that: /// - /// - `cp437_grid` points to a valid `SPCp437Grid` + /// - `cp437_grid` points to a valid [SPCp437Grid] /// - `cp437_grid` is not used concurrently or after cp437_grid call - /// - `cp437_grid` was not passed to another consuming function, e.g. to create a `SPCommand` + /// - `cp437_grid` was not passed to another consuming function, e.g. to create a [SPCommand] /// [DllImport(__DllName, EntryPoint = "sp_cp437_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_cp437_grid_free(Cp437Grid* cp437_grid); @@ -836,20 +1192,21 @@ namespace ServicePoint.BindGen /// /// # Panics /// - /// When accessing `x` or `y` out of bounds. + /// - when `cp437_grid` is NULL + /// - when accessing `x` or `y` out of bounds /// /// # Safety /// /// The caller has to make sure that: /// - /// - `cp437_grid` points to a valid `SPCp437Grid` + /// - `cp437_grid` points to a valid [SPCp437Grid] /// - `cp437_grid` is not written to concurrently /// [DllImport(__DllName, EntryPoint = "sp_cp437_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern byte sp_cp437_grid_get(Cp437Grid* cp437_grid, nuint x, nuint y); /// - /// Sets the value of the specified position in the `SPCp437Grid`. + /// Sets the value of the specified position in the [SPCp437Grid]. /// /// # Arguments /// @@ -861,129 +1218,158 @@ namespace ServicePoint.BindGen /// /// # Panics /// - /// When accessing `x` or `y` out of bounds. + /// - when `cp437_grid` is NULL + /// - when accessing `x` or `y` out of bounds /// /// # Safety /// /// The caller has to make sure that: /// - /// - `cp437_grid` points to a valid `SPBitVec` + /// - `cp437_grid` points to a valid [SPBitVec] /// - `cp437_grid` is not written to or read from concurrently /// [DllImport(__DllName, EntryPoint = "sp_cp437_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_cp437_grid_set(Cp437Grid* cp437_grid, nuint x, nuint y, byte value); /// - /// Sets the value of all cells in the `SPCp437Grid`. + /// Sets the value of all cells in the [SPCp437Grid]. /// /// # Arguments /// /// - `cp437_grid`: instance to write to /// - `value`: the value to set all cells to /// + /// # Panics + /// + /// - when `cp437_grid` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `cp437_grid` points to a valid `SPCp437Grid` + /// - `cp437_grid` points to a valid [SPCp437Grid] /// - `cp437_grid` is not written to or read from concurrently /// [DllImport(__DllName, EntryPoint = "sp_cp437_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_cp437_grid_fill(Cp437Grid* cp437_grid, byte value); /// - /// Gets the width of the `SPCp437Grid` instance. + /// Gets the width of the [SPCp437Grid] instance. /// /// # Arguments /// /// - `cp437_grid`: instance to read from /// + /// # Panics + /// + /// - when `cp437_grid` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `cp437_grid` points to a valid `SPCp437Grid` + /// - `cp437_grid` points to a valid [SPCp437Grid] /// [DllImport(__DllName, EntryPoint = "sp_cp437_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern nuint sp_cp437_grid_width(Cp437Grid* cp437_grid); /// - /// Gets the height of the `SPCp437Grid` instance. + /// Gets the height of the [SPCp437Grid] instance. /// /// # Arguments /// /// - `cp437_grid`: instance to read from /// + /// # Panics + /// + /// - when `cp437_grid` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `cp437_grid` points to a valid `SPCp437Grid` + /// - `cp437_grid` points to a valid [SPCp437Grid] /// [DllImport(__DllName, EntryPoint = "sp_cp437_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern nuint sp_cp437_grid_height(Cp437Grid* cp437_grid); /// - /// Gets an unsafe reference to the data of the `SPCp437Grid` instance. + /// Gets an unsafe reference to the data of the [SPCp437Grid] instance. /// /// Will never return NULL. /// + /// # Panics + /// + /// - when `cp437_grid` is NULL + /// /// ## Safety /// /// The caller has to make sure that: /// - /// - `cp437_grid` points to a valid `SPCp437Grid` - /// - 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 + /// - `cp437_grid` points to a valid [SPCp437Grid] + /// - 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 /// [DllImport(__DllName, EntryPoint = "sp_cp437_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern ByteSlice sp_cp437_grid_unsafe_data_ref(Cp437Grid* cp437_grid); /// - /// Turns a `SPCommand` into a `SPPacket`. - /// The `SPCommand` gets consumed. + /// Turns a [SPCommand] into a [SPPacket]. + /// The [SPCommand] gets consumed. /// /// Will never return NULL. /// + /// # Panics + /// + /// - when `command` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `SPCommand` points to a valid instance of `SPCommand` - /// - `SPCommand` is not used concurrently or after this call - /// - the returned `SPPacket` instance is freed in some way, either by using a consuming function or + /// - [SPCommand] points to a valid instance of [SPCommand] + /// - [SPCommand] is not used concurrently or after this call + /// - the returned [SPPacket] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_packet_free`. /// [DllImport(__DllName, EntryPoint = "sp_packet_from_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern Packet* sp_packet_from_command(Command* command); /// - /// Tries to load a `SPPacket` from the passed array with the specified length. + /// Tries to load a [SPPacket] from the passed array with the specified length. /// /// returns: NULL in case of an error, pointer to the allocated packet otherwise /// + /// # Panics + /// + /// - when `data` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// /// - `data` points to a valid memory region of at least `length` bytes /// - `data` is not written to concurrently - /// - the returned `SPPacket` instance is freed in some way, either by using a consuming function or + /// - the returned [SPPacket] instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_packet_free`. /// [DllImport(__DllName, EntryPoint = "sp_packet_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern Packet* sp_packet_try_load(byte* data, nuint length); /// - /// Clones a `SPPacket`. + /// Clones a [SPPacket]. /// /// Will never return NULL. /// + /// # Panics + /// + /// - when `packet` is NULL + /// /// # Safety /// /// The caller has to make sure that: /// - /// - `packet` points to a valid `SPPacket` + /// - `packet` points to a valid [SPPacket] /// - `packet` is not written to concurrently /// - the returned instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_packet_free`. @@ -992,212 +1378,28 @@ namespace ServicePoint.BindGen public static extern Packet* sp_packet_clone(Packet* packet); /// - /// Deallocates a `SPPacket`. + /// Deallocates a [SPPacket]. + /// + /// # Panics + /// + /// - when `sp_packet_free` is NULL /// /// # Safety /// /// The caller has to make sure that: /// - /// - `packet` points to a valid `SPPacket` + /// - `packet` points to a valid [SPPacket] /// - `packet` is not used concurrently or after this call /// [DllImport(__DllName, EntryPoint = "sp_packet_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_packet_free(Packet* packet); - /// - /// Creates a new `SPPixelGrid` with the specified dimensions. - /// - /// # Arguments - /// - /// - `width`: size in pixels in x-direction - /// - `height`: size in pixels in y-direction - /// - /// returns: `SPPixelGrid` initialized to all pixels off. Will never return NULL. - /// - /// # Panics - /// - /// - when the width is not dividable by 8 - /// - /// # 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_pixel_grid_free`. - /// - [DllImport(__DllName, EntryPoint = "sp_pixel_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern PixelGrid* sp_pixel_grid_new(nuint width, nuint height); - - /// - /// Loads a `SPPixelGrid` with the specified dimensions from the provided data. - /// - /// # Arguments - /// - /// - `width`: size in pixels in x-direction - /// - `height`: size in pixels in y-direction - /// - /// returns: `SPPixelGrid` that contains a copy of the provided data. Will never return NULL. - /// - /// # Panics - /// - /// - when the dimensions and data size do not match exactly. - /// - when the width is not dividable by 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_pixel_grid_free`. - /// - [DllImport(__DllName, EntryPoint = "sp_pixel_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern PixelGrid* sp_pixel_grid_load(nuint width, nuint height, byte* data, nuint data_length); - - /// - /// Clones a `SPPixelGrid`. - /// - /// Will never return NULL. - /// - /// # Safety - /// - /// The caller has to make sure that: - /// - /// - `pixel_grid` points to a valid `SPPixelGrid` - /// - `pixel_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_pixel_grid_free`. - /// - [DllImport(__DllName, EntryPoint = "sp_pixel_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern PixelGrid* sp_pixel_grid_clone(PixelGrid* pixel_grid); - - /// - /// Deallocates a `SPPixelGrid`. - /// - /// # Safety - /// - /// The caller has to make sure that: - /// - /// - `pixel_grid` points to a valid `SPPixelGrid` - /// - `pixel_grid` is not used concurrently or after pixel_grid call - /// - `pixel_grid` was not passed to another consuming function, e.g. to create a `SPCommand` - /// - [DllImport(__DllName, EntryPoint = "sp_pixel_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_pixel_grid_free(PixelGrid* pixel_grid); - - /// - /// Gets the current value at the specified position in the `SPPixelGrid`. - /// - /// # Arguments - /// - /// - `pixel_grid`: instance to read from - /// - `x` and `y`: position of the cell to read - /// - /// # Panics - /// - /// When accessing `x` or `y` out of bounds. - /// - /// # Safety - /// - /// The caller has to make sure that: - /// - /// - `pixel_grid` points to a valid `SPPixelGrid` - /// - `pixel_grid` is not written to concurrently - /// - [DllImport(__DllName, EntryPoint = "sp_pixel_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - [return: MarshalAs(UnmanagedType.U1)] - public static extern bool sp_pixel_grid_get(PixelGrid* pixel_grid, nuint x, nuint y); - - /// - /// Sets the value of the specified position in the `SPPixelGrid`. - /// - /// # Arguments - /// - /// - `pixel_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 accessing `x` or `y` out of bounds. - /// - /// # Safety - /// - /// The caller has to make sure that: - /// - /// - `pixel_grid` points to a valid `SPPixelGrid` - /// - `pixel_grid` is not written to or read from concurrently - /// - [DllImport(__DllName, EntryPoint = "sp_pixel_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_pixel_grid_set(PixelGrid* pixel_grid, nuint x, nuint y, [MarshalAs(UnmanagedType.U1)] bool value); - - /// - /// Sets the state of all pixels in the `SPPixelGrid`. - /// - /// # Arguments - /// - /// - `pixel_grid`: instance to write to - /// - `value`: the value to set all pixels to - /// - /// # Safety - /// - /// The caller has to make sure that: - /// - /// - `pixel_grid` points to a valid `SPPixelGrid` - /// - `pixel_grid` is not written to or read from concurrently - /// - [DllImport(__DllName, EntryPoint = "sp_pixel_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_pixel_grid_fill(PixelGrid* pixel_grid, [MarshalAs(UnmanagedType.U1)] bool value); - - /// - /// Gets the width in pixels of the `SPPixelGrid` instance. - /// - /// # Arguments - /// - /// - `pixel_grid`: instance to read from - /// - /// # Safety - /// - /// The caller has to make sure that: - /// - /// - `pixel_grid` points to a valid `SPPixelGrid` - /// - [DllImport(__DllName, EntryPoint = "sp_pixel_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern nuint sp_pixel_grid_width(PixelGrid* pixel_grid); - - /// - /// Gets the height in pixels of the `SPPixelGrid` instance. - /// - /// # Arguments - /// - /// - `pixel_grid`: instance to read from - /// - /// # Safety - /// - /// The caller has to make sure that: - /// - /// - `pixel_grid` points to a valid `SPPixelGrid` - /// - [DllImport(__DllName, EntryPoint = "sp_pixel_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern nuint sp_pixel_grid_height(PixelGrid* pixel_grid); - - /// - /// Gets an unsafe reference to the data of the `SPPixelGrid` instance. - /// - /// ## Safety - /// - /// The caller has to make sure that: - /// - /// - `pixel_grid` points to a valid `SPPixelGrid` - /// - the returned memory range is never accessed after the passed `SPPixelGrid` has been freed - /// - the returned memory range is never accessed concurrently, either via the `SPPixelGrid` or directly - /// - [DllImport(__DllName, EntryPoint = "sp_pixel_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern ByteSlice sp_pixel_grid_unsafe_data_ref(PixelGrid* pixel_grid); + } + [StructLayout(LayoutKind.Sequential)] + public unsafe partial struct Bitmap + { } [StructLayout(LayoutKind.Sequential)] @@ -1237,11 +1439,6 @@ namespace ServicePoint.BindGen { } - [StructLayout(LayoutKind.Sequential)] - public unsafe partial struct PixelGrid - { - } - public enum CompressionCode : ushort { diff --git a/crates/servicepoint_binding_cs/ServicePoint/BitVec.cs b/crates/servicepoint_binding_cs/ServicePoint/BitVec.cs index 2abe78c..ab697e0 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/BitVec.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/BitVec.cs @@ -8,7 +8,7 @@ public sealed class BitVec : SpNativeInstance { unsafe { - return new BitVec(NativeMethods.sp_bit_vec_new((nuint)size)); + return new BitVec(NativeMethods.sp_bitvec_new((nuint)size)); } } @@ -18,7 +18,7 @@ public sealed class BitVec : SpNativeInstance { fixed (byte* bytesPtr = bytes) { - return new BitVec(NativeMethods.sp_bit_vec_load(bytesPtr, (nuint)bytes.Length)); + return new BitVec(NativeMethods.sp_bitvec_load(bytesPtr, (nuint)bytes.Length)); } } } @@ -27,7 +27,7 @@ public sealed class BitVec : SpNativeInstance { unsafe { - return new BitVec(NativeMethods.sp_bit_vec_clone(Instance)); + return new BitVec(NativeMethods.sp_bitvec_clone(Instance)); } } @@ -37,14 +37,14 @@ public sealed class BitVec : SpNativeInstance { unsafe { - return NativeMethods.sp_bit_vec_get(Instance, (nuint)index); + return NativeMethods.sp_bitvec_get(Instance, (nuint)index); } } set { unsafe { - NativeMethods.sp_bit_vec_set(Instance, (nuint)index, value); + NativeMethods.sp_bitvec_set(Instance, (nuint)index, value); } } } @@ -53,7 +53,7 @@ public sealed class BitVec : SpNativeInstance { unsafe { - NativeMethods.sp_bit_vec_fill(Instance, value); + NativeMethods.sp_bitvec_fill(Instance, value); } } @@ -63,7 +63,7 @@ public sealed class BitVec : SpNativeInstance { unsafe { - return (int)NativeMethods.sp_bit_vec_len(Instance); + return (int)NativeMethods.sp_bitvec_len(Instance); } } } @@ -74,7 +74,7 @@ public sealed class BitVec : SpNativeInstance { unsafe { - var slice = NativeMethods.sp_bit_vec_unsafe_data_ref(Instance); + var slice = NativeMethods.sp_bitvec_unsafe_data_ref(Instance); return new Span(slice.start, (int)slice.length); } } @@ -84,5 +84,5 @@ public sealed class BitVec : SpNativeInstance { } - private protected override unsafe void Free() => NativeMethods.sp_bit_vec_free(Instance); + private protected override unsafe void Free() => NativeMethods.sp_bitvec_free(Instance); } diff --git a/crates/servicepoint_binding_cs/ServicePoint/PixelGrid.cs b/crates/servicepoint_binding_cs/ServicePoint/Bitmap.cs similarity index 50% rename from crates/servicepoint_binding_cs/ServicePoint/PixelGrid.cs rename to crates/servicepoint_binding_cs/ServicePoint/Bitmap.cs index 77e0cf3..6747483 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/PixelGrid.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/Bitmap.cs @@ -2,33 +2,33 @@ using ServicePoint.BindGen; namespace ServicePoint; -public sealed class PixelGrid : SpNativeInstance +public sealed class Bitmap : SpNativeInstance { - public static PixelGrid New(int width, int height) + public static Bitmap New(int width, int height) { unsafe { - return new PixelGrid(NativeMethods.sp_pixel_grid_new((nuint)width, (nuint)height)); + return new Bitmap(NativeMethods.sp_bitmap_new((nuint)width, (nuint)height)); } } - public static PixelGrid Load(int width, int height, Span bytes) + public static Bitmap Load(int width, int height, Span bytes) { unsafe { fixed (byte* bytesPtr = bytes) { - return new PixelGrid(NativeMethods.sp_pixel_grid_load((nuint)width, (nuint)height, bytesPtr, + return new Bitmap(NativeMethods.sp_bitmap_load((nuint)width, (nuint)height, bytesPtr, (nuint)bytes.Length)); } } } - public PixelGrid Clone() + public Bitmap Clone() { unsafe { - return new PixelGrid(NativeMethods.sp_pixel_grid_clone(Instance)); + return new Bitmap(NativeMethods.sp_bitmap_clone(Instance)); } } @@ -38,14 +38,14 @@ public sealed class PixelGrid : SpNativeInstance { unsafe { - return NativeMethods.sp_pixel_grid_get(Instance, (nuint)x, (nuint)y); + return NativeMethods.sp_bitmap_get(Instance, (nuint)x, (nuint)y); } } set { unsafe { - NativeMethods.sp_pixel_grid_set(Instance, (nuint)x, (nuint)y, value); + NativeMethods.sp_bitmap_set(Instance, (nuint)x, (nuint)y, value); } } } @@ -54,7 +54,7 @@ public sealed class PixelGrid : SpNativeInstance { unsafe { - NativeMethods.sp_pixel_grid_fill(Instance, value); + NativeMethods.sp_bitmap_fill(Instance, value); } } @@ -64,7 +64,7 @@ public sealed class PixelGrid : SpNativeInstance { unsafe { - return (int)NativeMethods.sp_pixel_grid_width(Instance); + return (int)NativeMethods.sp_bitmap_width(Instance); } } } @@ -75,7 +75,7 @@ public sealed class PixelGrid : SpNativeInstance { unsafe { - return (int)NativeMethods.sp_pixel_grid_height(Instance); + return (int)NativeMethods.sp_bitmap_height(Instance); } } } @@ -86,15 +86,15 @@ public sealed class PixelGrid : SpNativeInstance { unsafe { - var slice = NativeMethods.sp_pixel_grid_unsafe_data_ref(Instance); + var slice = NativeMethods.sp_bitmap_unsafe_data_ref(Instance); return new Span(slice.start, (int)slice.length); } } } - private unsafe PixelGrid(BindGen.PixelGrid* instance) : base(instance) + private unsafe Bitmap(BindGen.Bitmap* instance) : base(instance) { } - private protected override unsafe void Free() => NativeMethods.sp_pixel_grid_free(Instance); + private protected override unsafe void Free() => NativeMethods.sp_bitmap_free(Instance); } diff --git a/crates/servicepoint_binding_cs/ServicePoint/Command.cs b/crates/servicepoint_binding_cs/ServicePoint/Command.cs index e17c685..b62d511 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/Command.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/Command.cs @@ -105,11 +105,11 @@ public sealed class Command : SpNativeInstance } } - public static Command BitmapLinearWin(int x, int y, PixelGrid pixelGrid, CompressionCode compression) + public static Command BitmapLinearWin(int x, int y, Bitmap bitmap, CompressionCode compression) { unsafe { - return new Command(NativeMethods.sp_command_bitmap_linear_win((ushort)x, (ushort)y, pixelGrid.Into(), compression)); + return new Command(NativeMethods.sp_command_bitmap_linear_win((ushort)x, (ushort)y, bitmap.Into(), compression)); } } diff --git a/crates/servicepoint_binding_cs/ServicePoint/Constants.cs b/crates/servicepoint_binding_cs/ServicePoint/Constants.cs index 9980f64..14ea940 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/Constants.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/Constants.cs @@ -1,22 +1,24 @@ +using ServicePoint.BindGen; + namespace ServicePoint; public static class Constants { /// size of a single tile in one dimension - public const int TileSize = 8; + public const nuint TileSize = NativeMethods.SP_TILE_SIZE; /// tile count in the x-direction - public const int TileWidth = 56; + public const nuint TileWidth = NativeMethods.SP_TILE_WIDTH; /// tile count in the y-direction - public const int TileHeight = 20; + public const nuint TileHeight = NativeMethods.SP_TILE_SIZE; /// screen width in pixels - public const int PixelWidth = TileWidth * TileSize; + public const nuint PixelWidth = TileWidth * TileSize; /// screen height in pixels - public const int PixelHeight = TileHeight * TileSize; + public const nuint PixelHeight = TileHeight * TileSize; /// pixel count on whole screen - public const int PixelCount = PixelWidth * PixelHeight; + public const nuint PixelCount = PixelWidth * PixelHeight; } diff --git a/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj index c988f7d..0962c4c 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj +++ b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj @@ -11,7 +11,7 @@ ServicePoint - 0.9.1 + 0.10.0 Repository Authors None ServicePoint diff --git a/crates/servicepoint_binding_cs/build.rs b/crates/servicepoint_binding_cs/build.rs index 5287698..8caf589 100644 --- a/crates/servicepoint_binding_cs/build.rs +++ b/crates/servicepoint_binding_cs/build.rs @@ -8,8 +8,12 @@ fn main() { let mut builder = csbindgen::Builder::default(); - for source in fs::read_dir("../servicepoint_binding_c/src").unwrap() { - let path = source.unwrap().path(); + let mut paths = fs::read_dir("../servicepoint_binding_c/src").unwrap() + .map(|x| x.unwrap().path()) + .collect::>(); + paths.sort(); + + for path in paths { println!("cargo:rerun-if-changed={}", path.display()); builder = builder.input_extern_file(path); } diff --git a/crates/servicepoint_binding_cs/examples/lang_cs/Program.cs b/crates/servicepoint_binding_cs/examples/lang_cs/Program.cs index adfc32e..89c0eef 100644 --- a/crates/servicepoint_binding_cs/examples/lang_cs/Program.cs +++ b/crates/servicepoint_binding_cs/examples/lang_cs/Program.cs @@ -6,7 +6,7 @@ using var connection = Connection.Open("127.0.0.1:2342"); connection.Send(Command.Clear().IntoPacket()); connection.Send(Command.Brightness(128).IntoPacket()); -using var pixels = PixelGrid.New(Constants.PixelWidth, Constants.PixelHeight); +using var pixels = Bitmap.New(Constants.PixelWidth, Constants.PixelHeight); for (var offset = 0; offset < int.MaxValue; offset++) {