diff --git a/Cargo.lock b/Cargo.lock index 5bc28b4..01217c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -34,36 +34,36 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -101,9 +101,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "bzip2" @@ -147,9 +147,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.30" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" dependencies = [ "jobserver", "libc", @@ -204,15 +204,15 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] @@ -280,9 +280,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "flate2" @@ -329,9 +329,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" [[package]] name = "heck" @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.159" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "linux-raw-sys" @@ -457,9 +457,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -511,9 +511,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -523,9 +523,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -550,9 +550,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ "bitflags", "errno", @@ -569,18 +569,18 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -589,9 +589,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -610,7 +610,7 @@ dependencies = [ [[package]] name = "servicepoint" -version = "0.10.0" +version = "0.11.0" dependencies = [ "bitvec", "bzip2", @@ -620,13 +620,14 @@ dependencies = [ "once_cell", "rand", "rust-lzma", + "thiserror", "tungstenite", "zstd", ] [[package]] name = "servicepoint_binding_c" -version = "0.10.0" +version = "0.11.0" dependencies = [ "cbindgen", "servicepoint", @@ -634,7 +635,7 @@ dependencies = [ [[package]] name = "servicepoint_binding_cs" -version = "0.10.0" +version = "0.11.0" dependencies = [ "csbindgen", "servicepoint", @@ -666,9 +667,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.79" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -683,9 +684,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -696,18 +697,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index a8e0809..9bc62fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,10 @@ members = [ ] [workspace.package] -version = "0.10.0" +version = "0.11.0" [workspace.lints.rust] missing-docs = "warn" + +[workspace.dependencies] +thiserror = "1.0.69" \ No newline at end of file diff --git a/crates/servicepoint/Cargo.toml b/crates/servicepoint/Cargo.toml index f3d828d..3497c6c 100644 --- a/crates/servicepoint/Cargo.toml +++ b/crates/servicepoint/Cargo.toml @@ -22,6 +22,7 @@ rust-lzma = { version = "0.6.0", optional = true } rand = { version = "0.8", optional = true } tungstenite = { version = "0.24.0", optional = true } once_cell = { version = "1.20.2", optional = true } +thiserror.workspace = true [features] default = ["compression_lzma", "protocol_udp", "cp437"] diff --git a/crates/servicepoint/README.md b/crates/servicepoint/README.md index 5d69a44..0a1064f 100644 --- a/crates/servicepoint/README.md +++ b/crates/servicepoint/README.md @@ -17,7 +17,7 @@ cargo add servicepoint or ```toml [dependencies] -servicepoint = "0.10.0" +servicepoint = "0.11.0" ``` ## Examples diff --git a/crates/servicepoint/examples/announce.rs b/crates/servicepoint/examples/announce.rs index af78a54..66227a4 100644 --- a/crates/servicepoint/examples/announce.rs +++ b/crates/servicepoint/examples/announce.rs @@ -42,10 +42,10 @@ fn main() { } let text = cli.text.join("\n"); - let grid = CharGrid::from(&*text); - let cp437_grid = Cp437Grid::from(&grid); + let grid = CharGrid::from(text); + let grid = Cp437Grid::from(grid); connection - .send(Command::Cp437Data(Origin::ZERO, cp437_grid)) + .send(Command::Cp437Data(Origin::ZERO, grid)) .expect("sending text failed"); } diff --git a/crates/servicepoint/examples/websocket.rs b/crates/servicepoint/examples/websocket.rs index a0c43c0..207609e 100644 --- a/crates/servicepoint/examples/websocket.rs +++ b/crates/servicepoint/examples/websocket.rs @@ -5,20 +5,17 @@ use servicepoint::{ }; fn main() { - // make connection mut - let mut connection = + let connection = Connection::open_websocket("ws://localhost:8080".parse().unwrap()) .unwrap(); - // use send_mut instead of send - connection.send_mut(Command::Clear).unwrap(); + connection.send(Command::Clear).unwrap(); let mut pixels = Bitmap::max_sized(); pixels.fill(true); - // use send_mut instead of send connection - .send_mut(Command::BitmapLinearWin( + .send(Command::BitmapLinearWin( Origin::ZERO, pixels, CompressionCode::Lzma, diff --git a/crates/servicepoint/examples/wiping_clear.rs b/crates/servicepoint/examples/wiping_clear.rs index a3bf04a..6d85724 100644 --- a/crates/servicepoint/examples/wiping_clear.rs +++ b/crates/servicepoint/examples/wiping_clear.rs @@ -4,7 +4,7 @@ use std::time::Duration; use clap::Parser; -use servicepoint::{bitvec::prelude::BitVec, *}; +use servicepoint::*; #[derive(Parser, Debug)] struct Cli { @@ -33,12 +33,8 @@ fn main() { enabled_pixels.set(x_offset % PIXEL_WIDTH, y, false); } - // this works because the pixel grid has max size - let pixel_data: Vec = enabled_pixels.clone().into(); - let bit_vec = BitVec::from_vec(pixel_data); - connection - .send(Command::BitmapLinearAnd(0, bit_vec, CompressionCode::Lzma)) + .send(Command::BitmapLinearWin(Origin::ZERO, enabled_pixels.clone(), CompressionCode::Lzma)) .expect("could not send command to display"); thread::sleep(sleep_duration); } diff --git a/crates/servicepoint/src/bitmap.rs b/crates/servicepoint/src/bitmap.rs index 657e155..3d23706 100644 --- a/crates/servicepoint/src/bitmap.rs +++ b/crates/servicepoint/src/bitmap.rs @@ -2,14 +2,14 @@ use bitvec::order::Msb0; use bitvec::prelude::BitSlice; use bitvec::slice::IterMut; -use crate::{BitVec, DataRef, Grid, SpBitVec, PIXEL_HEIGHT, PIXEL_WIDTH}; +use crate::{BitVec, DataRef, Grid, PIXEL_HEIGHT, PIXEL_WIDTH}; /// A grid of pixels stored in packed bytes. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Bitmap { width: usize, height: usize, - bit_vec: SpBitVec, + bit_vec: BitVec, } impl Bitmap { @@ -175,6 +175,12 @@ impl From for Vec { } } +impl From for BitVec { + fn from(value: Bitmap) -> Self { + value.bit_vec + } +} + pub struct IterRows<'t> { bitmap: &'t Bitmap, row: usize, diff --git a/crates/servicepoint/src/brightness.rs b/crates/servicepoint/src/brightness.rs index e5a82b3..7787cc2 100644 --- a/crates/servicepoint/src/brightness.rs +++ b/crates/servicepoint/src/brightness.rs @@ -19,7 +19,7 @@ use rand::{ /// # let connection = Connection::open("127.0.0.1:2342").unwrap(); /// let result = connection.send(Command::Brightness(b)); /// ``` -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)] pub struct Brightness(u8); /// A grid containing brightness values. @@ -37,8 +37,21 @@ pub struct Brightness(u8); /// ``` pub type BrightnessGrid = PrimitiveGrid; +impl BrightnessGrid { + /// Like [Self::load], but ignoring any out-of-range brightness values + pub fn saturating_load(width: usize, height: usize, data: &[u8]) -> Self { + PrimitiveGrid::load(width, height, data).map(Brightness::saturating_from) + } +} + impl From for u8 { fn from(brightness: Brightness) -> Self { + Self::from(&brightness) + } +} + +impl From<&Brightness> for u8 { + fn from(brightness: &Brightness) -> Self { brightness.0 } } @@ -105,7 +118,7 @@ impl TryFrom> for BrightnessGrid { let brightnesses = value .iter() .map(|b| Brightness::try_from(*b)) - .collect::, _>>()?; + .collect::, _>>()?; Ok(BrightnessGrid::load( value.width(), value.height(), @@ -129,7 +142,7 @@ mod tests { #[test] fn brightness_from_u8() { assert_eq!(Err(100), Brightness::try_from(100)); - assert_eq!(Ok(Brightness(1)), Brightness::try_from(1)) + assert_eq!(Ok(Brightness(1)), Brightness::try_from(1)); } #[test] @@ -155,4 +168,10 @@ mod tests { assert_eq!(Brightness::MAX, Brightness::saturating_from(100)); assert_eq!(Brightness(5), Brightness::saturating_from(5)); } + + #[test] + fn saturating_load() { + assert_eq!(BrightnessGrid::load(2,2, &[Brightness::MAX, Brightness::MAX, Brightness::MIN, Brightness::MAX]), + BrightnessGrid::saturating_load(2,2, &[255u8, 23, 0, 42])); + } } diff --git a/crates/servicepoint/src/char_grid.rs b/crates/servicepoint/src/char_grid.rs new file mode 100644 index 0000000..1a9045c --- /dev/null +++ b/crates/servicepoint/src/char_grid.rs @@ -0,0 +1,129 @@ +use crate::primitive_grid::SeriesError; +use crate::{Grid, PrimitiveGrid}; + +/// A grid containing UTF-8 characters. +pub type CharGrid = PrimitiveGrid; + +impl CharGrid { + /// Copies a column from the grid as a String. + /// + /// Returns [None] if x is out of bounds. + pub fn get_col_str(&self, x: usize) -> Option { + Some(String::from_iter(self.get_col(x)?)) + } + + /// Copies a row from the grid as a String. + /// + /// Returns [None] if y is out of bounds. + pub fn get_row_str(&self, y: usize) -> Option { + Some(String::from_iter(self.get_row(y)?)) + } + + /// Overwrites a row in the grid with a str. + /// + /// Returns [SeriesError] if y is out of bounds or `row` is not of the correct size. + pub fn set_row_str( + &mut self, + y: usize, + value: &str, + ) -> Result<(), SeriesError> { + self.set_row(y, value.chars().collect::>().as_ref()) + } + + /// Overwrites a column in the grid with a str. + /// + /// Returns [SeriesError] if y is out of bounds or `row` is not of the correct size. + pub fn set_col_str( + &mut self, + x: usize, + value: &str, + ) -> Result<(), SeriesError> { + self.set_col(x, value.chars().collect::>().as_ref()) + } +} + +impl From<&str> for CharGrid { + fn from(value: &str) -> Self { + let value = value.replace("\r\n", "\n"); + 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() { + grid.set(x, y, char); + } + } + + grid + } +} + +impl From for CharGrid { + fn from(value: String) -> Self { + CharGrid::from(&*value) + } +} + +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") + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::Grid; + #[test] + fn col_str() { + let mut grid = CharGrid::new(2, 3); + assert_eq!(grid.get_col_str(2), None); + assert_eq!(grid.get_col_str(1), Some(String::from("\0\0\0"))); + assert_eq!(grid.set_col_str(1, "abc"), Ok(())); + assert_eq!(grid.get_col_str(1), Some(String::from("abc"))); + } + + #[test] + fn row_str() { + let mut grid = CharGrid::new(2, 3); + assert_eq!(grid.get_row_str(3), None); + assert_eq!(grid.get_row_str(1), Some(String::from("\0\0"))); + assert_eq!( + grid.set_row_str(1, "abc"), + Err(SeriesError::InvalidLength { + expected: 2, + actual: 3 + }) + ); + assert_eq!(grid.set_row_str(1, "ab"), Ok(())); + assert_eq!(grid.get_row_str(1), Some(String::from("ab"))); + } + + #[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/command.rs b/crates/servicepoint/src/command.rs index eead79d..462e448 100644 --- a/crates/servicepoint/src/command.rs +++ b/crates/servicepoint/src/command.rs @@ -1,11 +1,9 @@ -use bitvec::prelude::BitVec; - use crate::{ command_code::CommandCode, compression::into_decompressed, packet::{Header, Packet}, Bitmap, Brightness, BrightnessGrid, CompressionCode, Cp437Grid, Origin, - Pixels, PrimitiveGrid, SpBitVec, Tiles, TILE_SIZE, + Pixels, PrimitiveGrid, BitVec, Tiles, TILE_SIZE, }; /// Type alias for documenting the meaning of the u16 in enum values @@ -144,7 +142,7 @@ pub enum Command { /// once the starting row is full, overwriting will continue on column 0. /// /// The contained [BitVec] is always uncompressed. - BitmapLinear(Offset, SpBitVec, CompressionCode), + BitmapLinear(Offset, BitVec, CompressionCode), /// Set pixel data according to an and-mask starting at the offset. /// @@ -152,7 +150,7 @@ pub enum Command { /// once the starting row is full, overwriting will continue on column 0. /// /// The contained [BitVec] is always uncompressed. - BitmapLinearAnd(Offset, SpBitVec, CompressionCode), + BitmapLinearAnd(Offset, BitVec, CompressionCode), /// Set pixel data according to an or-mask starting at the offset. /// @@ -160,7 +158,7 @@ pub enum Command { /// once the starting row is full, overwriting will continue on column 0. /// /// The contained [BitVec] is always uncompressed. - BitmapLinearOr(Offset, SpBitVec, CompressionCode), + BitmapLinearOr(Offset, BitVec, CompressionCode), /// Set pixel data according to a xor-mask starting at the offset. /// @@ -168,7 +166,7 @@ pub enum Command { /// once the starting row is full, overwriting will continue on column 0. /// /// The contained [BitVec] is always uncompressed. - BitmapLinearXor(Offset, SpBitVec, CompressionCode), + BitmapLinearXor(Offset, BitVec, CompressionCode), /// Kills the udp daemon on the display, which usually results in a restart. /// @@ -214,21 +212,27 @@ pub enum Command { } /// Err values for [Command::try_from]. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, thiserror::Error)] pub enum TryFromPacketError { /// the contained command code does not correspond to a known command + #[error("The command code {0:?} does not correspond to a known command")] InvalidCommand(u16), /// the expected payload size was n, but size m was found + #[error("the expected payload size was {0}, but size {1} was found")] UnexpectedPayloadSize(usize, usize), /// Header fields not needed for the command have been used. /// /// Note that these commands would usually still work on the actual display. + #[error("Header fields not needed for the command have been used")] ExtraneousHeaderValues, /// The contained compression code is not known. This could be of disabled features. + #[error("The compression code {0:?} does not correspond to a known compression algorithm.")] InvalidCompressionCode(u16), /// Decompression of the payload failed. This can be caused by corrupted packets. + #[error("The decompression of the payload failed")] DecompressionFailed, /// The given brightness value is out of bounds + #[error("The given brightness value {0} is out of bounds.")] InvalidBrightness(u8), } @@ -374,7 +378,7 @@ impl Command { /// Helper method for Packets into `BitmapLinear*`-Commands fn packet_into_linear_bitmap( packet: Packet, - ) -> Result<(SpBitVec, CompressionCode), TryFromPacketError> { + ) -> Result<(BitVec, CompressionCode), TryFromPacketError> { let Packet { header: Header { diff --git a/crates/servicepoint/src/connection.rs b/crates/servicepoint/src/connection.rs index 5d4e902..9d53611 100644 --- a/crates/servicepoint/src/connection.rs +++ b/crates/servicepoint/src/connection.rs @@ -1,6 +1,5 @@ -use std::fmt::Debug; - use crate::packet::Packet; +use std::fmt::Debug; /// A connection to the display. /// @@ -35,27 +34,24 @@ pub enum Connection { /// [servicepoint-websocket-relay]: https://github.com/kaesaecracker/servicepoint-websocket-relay #[cfg(feature = "protocol_websocket")] WebSocket( - tungstenite::WebSocket< - tungstenite::stream::MaybeTlsStream, + std::sync::Mutex< + tungstenite::WebSocket< + tungstenite::stream::MaybeTlsStream, + >, >, ), /// A fake connection for testing that does not actually send anything. - /// - /// This variant allows immutable send. Fake, - - /// A fake connection for testing that does not actually send anything. - /// - /// This variant does not allow immutable send. - FakeMutableSend, } -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum SendError { - IoError(std::io::Error), + #[error("IO error occurred while sending")] + IoError(#[from] std::io::Error), #[cfg(feature = "protocol_websocket")] - WebsocketError(tungstenite::Error), + #[error("WebSocket error occurred while sending")] + WebsocketError(#[from] tungstenite::Error), } impl Connection { @@ -96,7 +92,7 @@ impl Connection { /// let uri = "ws://localhost:8080".parse().unwrap(); /// let mut connection = Connection::open_websocket(uri) /// .expect("could not connect"); - /// connection.send_mut(Command::Clear) + /// connection.send(Command::Clear) /// .expect("send failed"); /// ``` #[cfg(feature = "protocol_websocket")] @@ -111,25 +107,19 @@ impl Connection { let request = ClientRequestBuilder::new(uri).into_client_request()?; let (sock, _) = connect(request)?; - Ok(Self::WebSocket(sock)) + Ok(Self::WebSocket(std::sync::Mutex::new( + sock, + ))) } /// Send something packet-like to the display. Usually this is in the form of a Command. /// - /// This variant can only be used for connections that support immutable send, e.g. [Connection::Udp]. - /// - /// If you want to be able to switch the protocol, you should use [Self::send_mut] instead. - /// /// # Arguments /// /// - `packet`: the packet-like to send /// /// returns: true if packet was sent, otherwise false /// - /// # Panics - /// - /// If the connection does not support immutable send, e.g. for [Connection::WebSocket]. - /// /// # Examples /// /// ```rust @@ -150,59 +140,17 @@ impl Connection { .map_err(SendError::IoError) .map(move |_| ()) // ignore Ok value } - Connection::Fake => { - let _ = data; - Ok(()) - } - #[allow(unreachable_patterns)] // depends on features - _ => { - panic!("Connection {:?} does not support immutable send", self) - } - } - } - - /// Send something packet-like to the display. Usually this is in the form of a Command. - /// - /// This variant has to be used for connections that do not support immutable send, e.g. [Connection::WebSocket]. - /// - /// If you want to be able to switch the protocol, you should use this variant. - /// - /// # Arguments - /// - /// - `packet`: the packet-like to send - /// - /// returns: true if packet was sent, otherwise false - /// - /// # Examples - /// - /// ```rust - /// let mut connection = servicepoint::Connection::FakeMutableSend; - /// // turn off all pixels on display - /// connection.send_mut(servicepoint::Command::Clear) - /// .expect("send failed"); - /// ``` - pub fn send_mut( - &mut self, - packet: impl Into, - ) -> Result<(), SendError> { - match self { #[cfg(feature = "protocol_websocket")] Connection::WebSocket(socket) => { - let packet = packet.into(); - log::debug!("sending {packet:?}"); - let data: Vec = packet.into(); + let mut socket = socket.lock().unwrap(); socket .send(tungstenite::Message::Binary(data)) .map_err(SendError::WebsocketError) } - Connection::FakeMutableSend => { - let packet = packet.into(); - log::debug!("sending {packet:?}"); - let data: Vec = packet.into(); + Connection::Fake => { let _ = data; Ok(()) } - _ => self.send(packet), } } } @@ -211,7 +159,9 @@ impl Drop for Connection { fn drop(&mut self) { #[cfg(feature = "protocol_websocket")] if let Connection::WebSocket(sock) = self { - _ = sock.close(None); + _ = sock + .try_lock() + .map(move |mut sock| sock.close(None)); } } } @@ -227,19 +177,4 @@ mod tests { let packet = Packet::try_from(data).unwrap(); Connection::Fake.send(packet).unwrap() } - - #[test] - fn send_fake_mutable() { - let data: &[u8] = &[0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - let packet = Packet::try_from(data).unwrap(); - Connection::FakeMutableSend.send_mut(packet).unwrap() - } - - #[test] - #[should_panic] - fn send_fake_mutable_panic() { - let data: &[u8] = &[0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - let packet = Packet::try_from(data).unwrap(); - Connection::FakeMutableSend.send(packet).unwrap() - } } diff --git a/crates/servicepoint/src/cp437.rs b/crates/servicepoint/src/cp437.rs index f757594..bfd8b5a 100644 --- a/crates/servicepoint/src/cp437.rs +++ b/crates/servicepoint/src/cp437.rs @@ -10,19 +10,14 @@ use std::collections::HashMap; /// The encoding is currently not enforced. pub type Cp437Grid = PrimitiveGrid; -/// A grid containing UTF-8 characters. -pub type CharGrid = PrimitiveGrid; - -/// Errors that can occur when loading CP-437. -#[derive(Debug, PartialEq)] -pub enum Cp437LoadError { - /// Invalid character in input prevented loading - InvalidChar { - /// invalid character is at this position in input - index: usize, - /// the invalid character - char: char, - }, +/// The error occurring when loading an invalid character +#[derive(Debug, PartialEq, thiserror::Error)] +#[error("The character {char:?} at position {index} is not a valid CP437 character")] +pub struct InvalidCharError { + /// invalid character is at this position in input + index: usize, + /// the invalid character + char: char, } impl Cp437Grid { @@ -36,7 +31,7 @@ impl Cp437Grid { value: &str, width: usize, wrap: bool, - ) -> Result { + ) -> Result { assert!(width > 0); assert!(!value.is_empty()); @@ -46,7 +41,7 @@ impl Cp437Grid { for (index, char) in value.chars().enumerate() { if !char.is_ascii() { - return Err(Cp437LoadError::InvalidChar { index, char }); + return Err(InvalidCharError { index, char }); } let is_lf = char == '\n'; @@ -92,6 +87,7 @@ pub use feature_cp437::*; #[cfg(feature = "cp437")] mod feature_cp437 { use super::*; + use crate::CharGrid; /// An array of 256 elements, mapping most of the CP437 values to UTF-8 characters /// @@ -99,7 +95,7 @@ mod feature_cp437 { /// /// See /// - /// Mostly copied from https://github.com/kip93/cp437-tools. License: GPL-3.0 + /// Mostly copied from . License: GPL-3.0 #[rustfmt::skip] pub const CP437_TO_UTF8: [char; 256] = [ /* 0X */ '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '\n', '♂', '♀', '♪', '♫', '☼', @@ -143,44 +139,9 @@ mod feature_cp437 { } } - impl From<&str> for CharGrid { - fn from(value: &str) -> Self { - let value = value.replace("\r\n", "\n"); - 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() { - grid.set(x, y, char); - } - } - - 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") + impl From for Cp437Grid { + fn from(value: CharGrid) -> Self { + Cp437Grid::from(&value) } } @@ -236,7 +197,7 @@ mod tests { #[test] fn load_ascii_invalid() { assert_eq!( - Err(Cp437LoadError::InvalidChar { + Err(InvalidCharError { char: '🥶', index: 2 }), @@ -249,6 +210,7 @@ mod tests { #[cfg(feature = "cp437")] mod tests_feature_cp437 { use super::*; + use crate::CharGrid; #[test] fn round_trip_cp437() { @@ -292,13 +254,4 @@ mod tests_feature_cp437 { 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/lib.rs b/crates/servicepoint/src/lib.rs index 39b4077..46478e1 100644 --- a/crates/servicepoint/src/lib.rs +++ b/crates/servicepoint/src/lib.rs @@ -38,23 +38,25 @@ 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::char_grid::CharGrid; pub use crate::command::{Command, Offset}; pub use crate::compression_code::CompressionCode; pub use crate::connection::Connection; -pub use crate::cp437::{CharGrid, Cp437Grid}; +pub use crate::cp437::Cp437Grid; pub use crate::data_ref::DataRef; pub use crate::grid::Grid; pub use crate::origin::{Origin, Pixels, Tiles}; -pub use crate::primitive_grid::PrimitiveGrid; +pub use crate::primitive_grid::{PrimitiveGrid, SeriesError}; -type SpBitVec = BitVec; +/// An alias for the specific type of [bitvec::prelude::BitVec] used. +pub type BitVec = bitvec::prelude::BitVec; mod bitmap; mod brightness; +mod char_grid; mod command; mod command_code; mod compression; diff --git a/crates/servicepoint/src/primitive_grid.rs b/crates/servicepoint/src/primitive_grid.rs index 69dcf0f..366f0ca 100644 --- a/crates/servicepoint/src/primitive_grid.rs +++ b/crates/servicepoint/src/primitive_grid.rs @@ -13,6 +13,27 @@ pub struct PrimitiveGrid { data: Vec, } +/// Error type for methods that change a whole column or row at once +#[derive(thiserror::Error, Debug, PartialEq)] +pub enum SeriesError { + #[error("The index {index} was out of bounds for size {size}")] + /// The index {index} was out of bounds for size {size} + OutOfBounds { + /// the index where access was tried + index: usize, + /// the size in that direction + size: usize, + }, + #[error("The provided series was expected to have a length of {expected}, but was {actual}")] + /// The provided series was expected to have a length of {expected}, but was {actual} + InvalidLength { + /// actual size of the provided series + actual: usize, + /// expected size + expected: usize, + }, +} + impl PrimitiveGrid { /// Creates a new [PrimitiveGrid] with the specified dimensions. /// @@ -126,6 +147,8 @@ impl PrimitiveGrid { /// let grid: BrightnessGrid = grid.map(Brightness::saturating_from); /// let command = Command::CharBrightness(Origin::ZERO, grid); /// ``` + /// [Brightness]: [crate::Brightness] + /// [Command]: [crate::Command] pub fn map(&self, f: F) -> PrimitiveGrid where TConverted: PrimitiveGridType, @@ -138,6 +161,81 @@ impl PrimitiveGrid { .collect::>(); PrimitiveGrid::load(self.width(), self.height(), &data) } + + /// Copies a row from the grid. + /// + /// Returns [None] if y is out of bounds. + pub fn get_row(&self, y: usize) -> Option> { + self.data + .chunks_exact(self.width()) + .nth(y) + .map(|row| row.to_vec()) + } + + /// Copies a column from the grid. + /// + /// Returns [None] if x is out of bounds. + pub fn get_col(&self, x: usize) -> Option> { + self.data + .chunks_exact(self.width()) + .map(|row| row.get(x).copied()) + .collect() + } + + /// Overwrites a column in the grid. + /// + /// Returns [Err] if x is out of bounds or `col` is not of the correct size. + pub fn set_col(&mut self, x: usize, col: &[T]) -> Result<(), SeriesError> { + if col.len() != self.height() { + return Err(SeriesError::InvalidLength { + expected: self.height(), + actual: col.len(), + }); + } + let width = self.width(); + if self + .data + .chunks_exact_mut(width) + .zip(col.iter()) + .map(|(row, column_value)| { + row.get_mut(x).map(move |cell| *cell = *column_value) + }) + .all(|cell| cell.is_some()) + { + Ok(()) + } else { + Err(SeriesError::OutOfBounds { + index: x, + size: width, + }) + } + } + + /// Overwrites a row in the grid. + /// + /// Returns [Err] if y is out of bounds or `row` is not of the correct size. + pub fn set_row(&mut self, y: usize, row: &[T]) -> Result<(), SeriesError> { + let width = self.width(); + if row.len() != width { + return Err(SeriesError::InvalidLength { + expected: width, + actual: row.len(), + }); + } + + let chunk = match self.data.chunks_exact_mut(width).nth(y) { + Some(row) => row, + None => { + return Err(SeriesError::OutOfBounds { + size: self.height(), + index: y, + }) + } + }; + + chunk.copy_from_slice(row); + Ok(()) + } } impl Grid for PrimitiveGrid { @@ -225,7 +323,7 @@ impl<'t, T: PrimitiveGridType> Iterator for IterRows<'t, T> { #[cfg(test)] mod tests { - use crate::{DataRef, Grid, PrimitiveGrid}; + use crate::{DataRef, Grid, PrimitiveGrid, SeriesError}; #[test] fn fill() { @@ -347,4 +445,46 @@ mod tests { assert_eq!(grid.get_optional(0, 0), Some(5)); assert_eq!(grid.get_optional(0, 8), None); } + + #[test] + fn col() { + let mut grid = PrimitiveGrid::load(2, 3, &[0, 1, 2, 3, 4, 5]); + assert_eq!(grid.get_col(0), Some(vec![0, 2, 4])); + assert_eq!(grid.get_col(1), Some(vec![1, 3, 5])); + assert_eq!(grid.get_col(2), None); + assert_eq!(grid.set_col(0, &[5, 7, 9]), Ok(())); + assert_eq!( + grid.set_col(2, &[5, 7, 9]), + Err(SeriesError::OutOfBounds { size: 2, index: 2 }) + ); + assert_eq!( + grid.set_col(0, &[5, 7]), + Err(SeriesError::InvalidLength { + expected: 3, + actual: 2 + }) + ); + assert_eq!(grid.get_col(0), Some(vec![5, 7, 9])); + } + + #[test] + fn row() { + let mut grid = PrimitiveGrid::load(2, 3, &[0, 1, 2, 3, 4, 5]); + assert_eq!(grid.get_row(0), Some(vec![0, 1])); + assert_eq!(grid.get_row(2), Some(vec![4, 5])); + assert_eq!(grid.get_row(3), None); + assert_eq!(grid.set_row(0, &[5, 7]), Ok(())); + assert_eq!(grid.get_row(0), Some(vec![5, 7])); + assert_eq!( + grid.set_row(3, &[5, 7]), + Err(SeriesError::OutOfBounds { size: 3, index: 3 }) + ); + assert_eq!( + grid.set_row(2, &[5, 7, 3]), + Err(SeriesError::InvalidLength { + expected: 2, + actual: 3 + }) + ); + } } diff --git a/crates/servicepoint_binding_c/Cargo.toml b/crates/servicepoint_binding_c/Cargo.toml index d8dd0a1..91122d3 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.10.0" +version = "0.11.0" path = "../servicepoint" features = ["all_compressions"] 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 fec0ff0..0d716d1 100644 --- a/crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h +++ b/crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h @@ -144,6 +144,8 @@ typedef struct SPBrightnessGrid SPBrightnessGrid; * sp_connection_send_command(connection, sp_command_clear()); * sp_connection_send_command(connection, sp_command_brightness(5)); * ``` + * + * [SPConnection]: [crate::SPConnection] */ typedef struct SPCommand SPCommand; @@ -266,6 +268,8 @@ void sp_bitmap_fill(SPBitmap *bitmap, bool value); * - `bitmap` points to a valid [SPBitmap] * - `bitmap` is not used concurrently or after bitmap call * - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] + * + * [SPCommand]: [crate::SPCommand] */ void sp_bitmap_free(SPBitmap *bitmap); @@ -479,6 +483,8 @@ void sp_bitvec_fill(SPBitVec *bit_vec, bool value); * - `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] + * + * [SPCommand]: [crate::SPCommand] */ void sp_bitvec_free(SPBitVec *bit_vec); @@ -695,6 +701,8 @@ void sp_brightness_grid_fill(SPBrightnessGrid *brightness_grid, uint8_t value); * - `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] + * + * [SPCommand]: [crate::SPCommand] */ void sp_brightness_grid_free(SPBrightnessGrid *brightness_grid); @@ -805,7 +813,7 @@ 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 [SPBrightnessGrid] * - `brightness_grid` is not written to or read from concurrently */ void sp_brightness_grid_set(SPBrightnessGrid *brightness_grid, @@ -867,7 +875,7 @@ size_t sp_brightness_grid_width(const SPBrightnessGrid *brightness_grid); * * The passed [SPBitVec] gets consumed. * - * Returns: a new [Command::BitmapLinear] instance. Will never return NULL. + * Returns: a new [servicepoint::Command::BitmapLinear] instance. Will never return NULL. * * # Panics * @@ -898,7 +906,7 @@ SPCommand *sp_command_bitmap_linear(size_t offset, * * The passed [SPBitVec] gets consumed. * - * Returns: a new [Command::BitmapLinearAnd] instance. Will never return NULL. + * Returns: a new [servicepoint::Command::BitmapLinearAnd] instance. Will never return NULL. * * # Panics * @@ -929,7 +937,7 @@ SPCommand *sp_command_bitmap_linear_and(size_t offset, * * The passed [SPBitVec] gets consumed. * - * Returns: a new [Command::BitmapLinearOr] instance. Will never return NULL. + * Returns: a new [servicepoint::Command::BitmapLinearOr] instance. Will never return NULL. * * # Panics * @@ -955,7 +963,7 @@ SPCommand *sp_command_bitmap_linear_or(size_t offset, * * The passed [SPBitmap] gets consumed. * - * Returns: a new [Command::BitmapLinearWin] instance. Will never return NULL. + * Returns: a new [servicepoint::Command::BitmapLinearWin] instance. Will never return NULL. * * # Panics * @@ -987,7 +995,7 @@ SPCommand *sp_command_bitmap_linear_win(size_t x, * * The passed [SPBitVec] gets consumed. * - * Returns: a new [Command::BitmapLinearXor] instance. Will never return NULL. + * Returns: a new [servicepoint::Command::BitmapLinearXor] instance. Will never return NULL. * * # Panics * @@ -1011,7 +1019,7 @@ SPCommand *sp_command_bitmap_linear_xor(size_t offset, /** * Set the brightness of all tiles to the same value. * - * Returns: a new [Command::Brightness] instance. Will never return NULL. + * Returns: a new [servicepoint::Command::Brightness] instance. Will never return NULL. * * # Panics * @@ -1031,7 +1039,7 @@ SPCommand *sp_command_brightness(uint8_t brightness); * * The passed [SPBrightnessGrid] gets consumed. * - * Returns: a new [Command::CharBrightness] instance. Will never return NULL. + * Returns: a new [servicepoint::Command::CharBrightness] instance. Will never return NULL. * * # Panics * @@ -1055,7 +1063,7 @@ SPCommand *sp_command_char_brightness(size_t x, * * Does not affect brightness. * - * Returns: a new [Command::Clear] instance. Will never return NULL. + * Returns: a new [servicepoint::Command::Clear] instance. Will never return NULL. * * # Examples * @@ -1097,7 +1105,7 @@ SPCommand *sp_command_clone(const SPCommand *command); * * The passed [SPCp437Grid] gets consumed. * - * Returns: a new [Command::Cp437Data] instance. Will never return NULL. + * Returns: a new [servicepoint::Command::Cp437Data] instance. Will never return NULL. * * # Panics * @@ -1119,7 +1127,7 @@ SPCommand *sp_command_cp437_data(size_t x, /** * A yet-to-be-tested command. * - * Returns: a new `Command::FadeOut` instance. Will never return NULL. + * Returns: a new [servicepoint::Command::FadeOut] instance. Will never return NULL. * * # Safety * @@ -1159,7 +1167,7 @@ void sp_command_free(SPCommand *command); * * Please do not send this in your normal program flow. * - * Returns: a new [Command::HardReset] instance. Will never return NULL. + * Returns: a new [servicepoint::Command::HardReset] instance. Will never return NULL. * * # Safety * @@ -1328,6 +1336,8 @@ void sp_cp437_grid_fill(SPCp437Grid *cp437_grid, uint8_t value); * - `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] + * + * [SPCommand]: [crate::SPCommand] */ void sp_cp437_grid_free(SPCp437Grid *cp437_grid); @@ -1433,6 +1443,8 @@ SPCp437Grid *sp_cp437_grid_new(size_t width, * * - `cp437_grid` points to a valid [SPBitVec] * - `cp437_grid` is not written to or read from concurrently + * + * [SPBitVec]: [crate::SPBitVec] */ void sp_cp437_grid_set(SPCp437Grid *cp437_grid, size_t x, diff --git a/crates/servicepoint_binding_c/src/bitmap.rs b/crates/servicepoint_binding_c/src/bitmap.rs index b327fd2..a7ae48a 100644 --- a/crates/servicepoint_binding_c/src/bitmap.rs +++ b/crates/servicepoint_binding_c/src/bitmap.rs @@ -124,6 +124,8 @@ pub unsafe extern "C" fn sp_bitmap_clone( /// - `bitmap` points to a valid [SPBitmap] /// - `bitmap` is not used concurrently or after bitmap call /// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] +/// +/// [SPCommand]: [crate::SPCommand] #[no_mangle] pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) { assert!(!bitmap.is_null()); diff --git a/crates/servicepoint_binding_c/src/bitvec.rs b/crates/servicepoint_binding_c/src/bitvec.rs index 7f2258a..4ee5f52 100644 --- a/crates/servicepoint_binding_c/src/bitvec.rs +++ b/crates/servicepoint_binding_c/src/bitvec.rs @@ -123,6 +123,8 @@ pub unsafe extern "C" fn sp_bitvec_clone( /// - `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] +/// +/// [SPCommand]: [crate::SPCommand] #[no_mangle] pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) { assert!(!bit_vec.is_null()); diff --git a/crates/servicepoint_binding_c/src/brightness_grid.rs b/crates/servicepoint_binding_c/src/brightness_grid.rs index 3c94b57..04187d7 100644 --- a/crates/servicepoint_binding_c/src/brightness_grid.rs +++ b/crates/servicepoint_binding_c/src/brightness_grid.rs @@ -133,6 +133,8 @@ pub unsafe extern "C" fn sp_brightness_grid_clone( /// - `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] +/// +/// [SPCommand]: [crate::SPCommand] #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_free( brightness_grid: *mut SPBrightnessGrid, @@ -191,7 +193,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 [SPBrightnessGrid] /// - `brightness_grid` is not written to or read from concurrently #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_set( diff --git a/crates/servicepoint_binding_c/src/command.rs b/crates/servicepoint_binding_c/src/command.rs index a4ebc1a..1c56d07 100644 --- a/crates/servicepoint_binding_c/src/command.rs +++ b/crates/servicepoint_binding_c/src/command.rs @@ -23,6 +23,8 @@ use crate::{ /// sp_connection_send_command(connection, sp_command_clear()); /// sp_connection_send_command(connection, sp_command_brightness(5)); /// ``` +/// +/// [SPConnection]: [crate::SPConnection] pub struct SPCommand(pub(crate) servicepoint::Command); impl Clone for SPCommand { @@ -90,7 +92,7 @@ pub unsafe extern "C" fn sp_command_clone( /// /// Does not affect brightness. /// -/// Returns: a new [Command::Clear] instance. Will never return NULL. +/// Returns: a new [servicepoint::Command::Clear] instance. Will never return NULL. /// /// # Examples /// @@ -114,7 +116,7 @@ pub unsafe extern "C" fn sp_command_clear() -> NonNull { /// /// Please do not send this in your normal program flow. /// -/// Returns: a new [Command::HardReset] instance. Will never return NULL. +/// Returns: a new [servicepoint::Command::HardReset] instance. Will never return NULL. /// /// # Safety /// @@ -130,7 +132,7 @@ pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull { /// A yet-to-be-tested command. /// -/// Returns: a new `Command::FadeOut` instance. Will never return NULL. +/// Returns: a new [servicepoint::Command::FadeOut] instance. Will never return NULL. /// /// # Safety /// @@ -146,7 +148,7 @@ pub unsafe extern "C" fn sp_command_fade_out() -> NonNull { /// Set the brightness of all tiles to the same value. /// -/// Returns: a new [Command::Brightness] instance. Will never return NULL. +/// Returns: a new [servicepoint::Command::Brightness] instance. Will never return NULL. /// /// # Panics /// @@ -174,7 +176,7 @@ pub unsafe extern "C" fn sp_command_brightness( /// /// The passed [SPBrightnessGrid] gets consumed. /// -/// Returns: a new [Command::CharBrightness] instance. Will never return NULL. +/// Returns: a new [servicepoint::Command::CharBrightness] instance. Will never return NULL. /// /// # Panics /// @@ -211,7 +213,7 @@ pub unsafe extern "C" fn sp_command_char_brightness( /// /// The passed [SPBitVec] gets consumed. /// -/// Returns: a new [Command::BitmapLinear] instance. Will never return NULL. +/// Returns: a new [servicepoint::Command::BitmapLinear] instance. Will never return NULL. /// /// # Panics /// @@ -254,7 +256,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear( /// /// The passed [SPBitVec] gets consumed. /// -/// Returns: a new [Command::BitmapLinearAnd] instance. Will never return NULL. +/// Returns: a new [servicepoint::Command::BitmapLinearAnd] instance. Will never return NULL. /// /// # Panics /// @@ -297,7 +299,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_and( /// /// The passed [SPBitVec] gets consumed. /// -/// Returns: a new [Command::BitmapLinearOr] instance. Will never return NULL. +/// Returns: a new [servicepoint::Command::BitmapLinearOr] instance. Will never return NULL. /// /// # Panics /// @@ -340,7 +342,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_or( /// /// The passed [SPBitVec] gets consumed. /// -/// Returns: a new [Command::BitmapLinearXor] instance. Will never return NULL. +/// Returns: a new [servicepoint::Command::BitmapLinearXor] instance. Will never return NULL. /// /// # Panics /// @@ -378,7 +380,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_xor( /// /// The passed [SPCp437Grid] gets consumed. /// -/// Returns: a new [Command::Cp437Data] instance. Will never return NULL. +/// Returns: a new [servicepoint::Command::Cp437Data] instance. Will never return NULL. /// /// # Panics /// @@ -410,7 +412,7 @@ pub unsafe extern "C" fn sp_command_cp437_data( /// /// The passed [SPBitmap] gets consumed. /// -/// Returns: a new [Command::BitmapLinearWin] instance. Will never return NULL. +/// Returns: a new [servicepoint::Command::BitmapLinearWin] instance. Will never return NULL. /// /// # Panics /// diff --git a/crates/servicepoint_binding_c/src/cp437_grid.rs b/crates/servicepoint_binding_c/src/cp437_grid.rs index b940ae4..32e2642 100644 --- a/crates/servicepoint_binding_c/src/cp437_grid.rs +++ b/crates/servicepoint_binding_c/src/cp437_grid.rs @@ -117,6 +117,8 @@ pub unsafe extern "C" fn sp_cp437_grid_clone( /// - `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] +/// +/// [SPCommand]: [crate::SPCommand] #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) { assert!(!cp437_grid.is_null()); @@ -172,6 +174,8 @@ pub unsafe extern "C" fn sp_cp437_grid_get( /// /// - `cp437_grid` points to a valid [SPBitVec] /// - `cp437_grid` is not written to or read from concurrently +/// +/// [SPBitVec]: [crate::SPBitVec] #[no_mangle] pub unsafe extern "C" fn sp_cp437_grid_set( cp437_grid: *mut SPCp437Grid, diff --git a/crates/servicepoint_binding_cs/Cargo.toml b/crates/servicepoint_binding_cs/Cargo.toml index caca7b9..01282ac 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.10.0", path = "../servicepoint_binding_c" } -servicepoint = { version = "0.10.0", path = "../servicepoint" } +servicepoint_binding_c = { version = "0.11.0", path = "../servicepoint_binding_c" } +servicepoint = { version = "0.11.0", path = "../servicepoint" } [lints] workspace = true diff --git a/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs b/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs index c8bb0a2..8f41ab4 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs @@ -108,6 +108,8 @@ namespace ServicePoint.BindGen /// - `bitmap` points to a valid [SPBitmap] /// - `bitmap` is not used concurrently or after bitmap call /// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] + /// + /// [SPCommand]: [crate::SPCommand] /// [DllImport(__DllName, EntryPoint = "sp_bitmap_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_bitmap_free(Bitmap* bitmap); @@ -321,6 +323,8 @@ namespace ServicePoint.BindGen /// - `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] + /// + /// [SPCommand]: [crate::SPCommand] /// [DllImport(__DllName, EntryPoint = "sp_bitvec_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_bitvec_free(BitVec* bit_vec); @@ -540,6 +544,8 @@ namespace ServicePoint.BindGen /// - `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] + /// + /// [SPCommand]: [crate::SPCommand] /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_brightness_grid_free(BrightnessGrid* brightness_grid); @@ -590,7 +596,7 @@ namespace ServicePoint.BindGen /// /// The caller has to make sure that: /// - /// - `brightness_grid` points to a valid [SPBitVec] + /// - `brightness_grid` points to a valid [SPBrightnessGrid] /// - `brightness_grid` is not written to or read from concurrently /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -737,7 +743,7 @@ namespace ServicePoint.BindGen /// /// Does not affect brightness. /// - /// Returns: a new [Command::Clear] instance. Will never return NULL. + /// Returns: a new [servicepoint::Command::Clear] instance. Will never return NULL. /// /// # Examples /// @@ -760,7 +766,7 @@ 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 [servicepoint::Command::HardReset] instance. Will never return NULL. /// /// # Safety /// @@ -775,7 +781,7 @@ namespace ServicePoint.BindGen /// /// A yet-to-be-tested command. /// - /// Returns: a new `Command::FadeOut` instance. Will never return NULL. + /// Returns: a new [servicepoint::Command::FadeOut] instance. Will never return NULL. /// /// # Safety /// @@ -790,7 +796,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 [servicepoint::Command::Brightness] instance. Will never return NULL. /// /// # Panics /// @@ -811,7 +817,7 @@ namespace ServicePoint.BindGen /// /// The passed [SPBrightnessGrid] gets consumed. /// - /// Returns: a new [Command::CharBrightness] instance. Will never return NULL. + /// Returns: a new [servicepoint::Command::CharBrightness] instance. Will never return NULL. /// /// # Panics /// @@ -839,7 +845,7 @@ namespace ServicePoint.BindGen /// /// The passed [SPBitVec] gets consumed. /// - /// Returns: a new [Command::BitmapLinear] instance. Will never return NULL. + /// Returns: a new [servicepoint::Command::BitmapLinear] instance. Will never return NULL. /// /// # Panics /// @@ -869,7 +875,7 @@ namespace ServicePoint.BindGen /// /// The passed [SPBitVec] gets consumed. /// - /// Returns: a new [Command::BitmapLinearAnd] instance. Will never return NULL. + /// Returns: a new [servicepoint::Command::BitmapLinearAnd] instance. Will never return NULL. /// /// # Panics /// @@ -899,7 +905,7 @@ namespace ServicePoint.BindGen /// /// The passed [SPBitVec] gets consumed. /// - /// Returns: a new [Command::BitmapLinearOr] instance. Will never return NULL. + /// Returns: a new [servicepoint::Command::BitmapLinearOr] instance. Will never return NULL. /// /// # Panics /// @@ -929,7 +935,7 @@ namespace ServicePoint.BindGen /// /// The passed [SPBitVec] gets consumed. /// - /// Returns: a new [Command::BitmapLinearXor] instance. Will never return NULL. + /// Returns: a new [servicepoint::Command::BitmapLinearXor] instance. Will never return NULL. /// /// # Panics /// @@ -954,7 +960,7 @@ namespace ServicePoint.BindGen /// /// The passed [SPCp437Grid] gets consumed. /// - /// Returns: a new [Command::Cp437Data] instance. Will never return NULL. + /// Returns: a new [servicepoint::Command::Cp437Data] instance. Will never return NULL. /// /// # Panics /// @@ -977,7 +983,7 @@ namespace ServicePoint.BindGen /// /// The passed [SPBitmap] gets consumed. /// - /// Returns: a new [Command::BitmapLinearWin] instance. Will never return NULL. + /// Returns: a new [servicepoint::Command::BitmapLinearWin] instance. Will never return NULL. /// /// # Panics /// @@ -1178,6 +1184,8 @@ namespace ServicePoint.BindGen /// - `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] + /// + /// [SPCommand]: [crate::SPCommand] /// [DllImport(__DllName, EntryPoint = "sp_cp437_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void sp_cp437_grid_free(Cp437Grid* cp437_grid); @@ -1227,6 +1235,8 @@ namespace ServicePoint.BindGen /// /// - `cp437_grid` points to a valid [SPBitVec] /// - `cp437_grid` is not written to or read from concurrently + /// + /// [SPBitVec]: [crate::SPBitVec] /// [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); diff --git a/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj index 0962c4c..e806186 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj +++ b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj @@ -11,7 +11,7 @@ ServicePoint - 0.10.0 + 0.11.0 Repository Authors None ServicePoint