Merge branch 'uniffi-prerequisites' into 'main'

see https://github.com/cccb/servicepoint/pull/19/
This commit is contained in:
Vinzenz Schroeter 2024-11-13 18:57:08 +01:00
commit 11ec30ca74
25 changed files with 496 additions and 276 deletions

103
Cargo.lock generated
View file

@ -19,9 +19,9 @@ dependencies = [
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.15" version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"anstyle-parse", "anstyle-parse",
@ -34,36 +34,36 @@ dependencies = [
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.8" version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]] [[package]]
name = "anstyle-parse" name = "anstyle-parse"
version = "0.2.5" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [ dependencies = [
"utf8parse", "utf8parse",
] ]
[[package]] [[package]]
name = "anstyle-query" name = "anstyle-query"
version = "1.1.1" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
name = "anstyle-wincon" name = "anstyle-wincon"
version = "3.0.4" version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -101,9 +101,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.7.2" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
[[package]] [[package]]
name = "bzip2" name = "bzip2"
@ -147,9 +147,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.1.30" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc", "libc",
@ -204,15 +204,15 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
version = "1.0.2" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.14" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@ -280,9 +280,9 @@ dependencies = [
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "2.1.1" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
[[package]] [[package]]
name = "flate2" name = "flate2"
@ -329,9 +329,9 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.0" version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
[[package]] [[package]]
name = "heck" name = "heck"
@ -403,9 +403,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.159" version = "0.2.162"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
@ -457,9 +457,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.87" version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -511,9 +511,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.11.0" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -523,9 +523,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.4.8" version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -550,9 +550,9 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.37" version = "0.38.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",
@ -569,18 +569,18 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.210" version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.210" version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -589,9 +589,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.128" version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@ -610,7 +610,7 @@ dependencies = [
[[package]] [[package]]
name = "servicepoint" name = "servicepoint"
version = "0.10.0" version = "0.11.0"
dependencies = [ dependencies = [
"bitvec", "bitvec",
"bzip2", "bzip2",
@ -620,13 +620,14 @@ dependencies = [
"once_cell", "once_cell",
"rand", "rand",
"rust-lzma", "rust-lzma",
"thiserror",
"tungstenite", "tungstenite",
"zstd", "zstd",
] ]
[[package]] [[package]]
name = "servicepoint_binding_c" name = "servicepoint_binding_c"
version = "0.10.0" version = "0.11.0"
dependencies = [ dependencies = [
"cbindgen", "cbindgen",
"servicepoint", "servicepoint",
@ -634,7 +635,7 @@ dependencies = [
[[package]] [[package]]
name = "servicepoint_binding_cs" name = "servicepoint_binding_cs"
version = "0.10.0" version = "0.11.0"
dependencies = [ dependencies = [
"csbindgen", "csbindgen",
"servicepoint", "servicepoint",
@ -666,9 +667,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.79" version = "2.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -683,9 +684,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.13.0" version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
@ -696,18 +697,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.64" version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.64" version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -8,7 +8,10 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "0.10.0" version = "0.11.0"
[workspace.lints.rust] [workspace.lints.rust]
missing-docs = "warn" missing-docs = "warn"
[workspace.dependencies]
thiserror = "1.0.69"

View file

@ -22,6 +22,7 @@ rust-lzma = { version = "0.6.0", optional = true }
rand = { version = "0.8", optional = true } rand = { version = "0.8", optional = true }
tungstenite = { version = "0.24.0", optional = true } tungstenite = { version = "0.24.0", optional = true }
once_cell = { version = "1.20.2", optional = true } once_cell = { version = "1.20.2", optional = true }
thiserror.workspace = true
[features] [features]
default = ["compression_lzma", "protocol_udp", "cp437"] default = ["compression_lzma", "protocol_udp", "cp437"]

View file

@ -17,7 +17,7 @@ cargo add servicepoint
or or
```toml ```toml
[dependencies] [dependencies]
servicepoint = "0.10.0" servicepoint = "0.11.0"
``` ```
## Examples ## Examples

View file

@ -42,10 +42,10 @@ fn main() {
} }
let text = cli.text.join("\n"); let text = cli.text.join("\n");
let grid = CharGrid::from(&*text); let grid = CharGrid::from(text);
let cp437_grid = Cp437Grid::from(&grid); let grid = Cp437Grid::from(grid);
connection connection
.send(Command::Cp437Data(Origin::ZERO, cp437_grid)) .send(Command::Cp437Data(Origin::ZERO, grid))
.expect("sending text failed"); .expect("sending text failed");
} }

View file

@ -5,20 +5,17 @@ use servicepoint::{
}; };
fn main() { fn main() {
// make connection mut let connection =
let mut connection =
Connection::open_websocket("ws://localhost:8080".parse().unwrap()) Connection::open_websocket("ws://localhost:8080".parse().unwrap())
.unwrap(); .unwrap();
// use send_mut instead of send connection.send(Command::Clear).unwrap();
connection.send_mut(Command::Clear).unwrap();
let mut pixels = Bitmap::max_sized(); let mut pixels = Bitmap::max_sized();
pixels.fill(true); pixels.fill(true);
// use send_mut instead of send
connection connection
.send_mut(Command::BitmapLinearWin( .send(Command::BitmapLinearWin(
Origin::ZERO, Origin::ZERO,
pixels, pixels,
CompressionCode::Lzma, CompressionCode::Lzma,

View file

@ -4,7 +4,7 @@ use std::time::Duration;
use clap::Parser; use clap::Parser;
use servicepoint::{bitvec::prelude::BitVec, *}; use servicepoint::*;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
struct Cli { struct Cli {
@ -33,12 +33,8 @@ fn main() {
enabled_pixels.set(x_offset % PIXEL_WIDTH, y, false); enabled_pixels.set(x_offset % PIXEL_WIDTH, y, false);
} }
// this works because the pixel grid has max size
let pixel_data: Vec<u8> = enabled_pixels.clone().into();
let bit_vec = BitVec::from_vec(pixel_data);
connection 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"); .expect("could not send command to display");
thread::sleep(sleep_duration); thread::sleep(sleep_duration);
} }

View file

@ -2,14 +2,14 @@ use bitvec::order::Msb0;
use bitvec::prelude::BitSlice; use bitvec::prelude::BitSlice;
use bitvec::slice::IterMut; 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. /// A grid of pixels stored in packed bytes.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Bitmap { pub struct Bitmap {
width: usize, width: usize,
height: usize, height: usize,
bit_vec: SpBitVec, bit_vec: BitVec,
} }
impl Bitmap { impl Bitmap {
@ -175,6 +175,12 @@ impl From<Bitmap> for Vec<u8> {
} }
} }
impl From<Bitmap> for BitVec {
fn from(value: Bitmap) -> Self {
value.bit_vec
}
}
pub struct IterRows<'t> { pub struct IterRows<'t> {
bitmap: &'t Bitmap, bitmap: &'t Bitmap,
row: usize, row: usize,

View file

@ -19,7 +19,7 @@ use rand::{
/// # let connection = Connection::open("127.0.0.1:2342").unwrap(); /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
/// let result = connection.send(Command::Brightness(b)); /// let result = connection.send(Command::Brightness(b));
/// ``` /// ```
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
pub struct Brightness(u8); pub struct Brightness(u8);
/// A grid containing brightness values. /// A grid containing brightness values.
@ -37,8 +37,21 @@ pub struct Brightness(u8);
/// ``` /// ```
pub type BrightnessGrid = PrimitiveGrid<Brightness>; pub type BrightnessGrid = PrimitiveGrid<Brightness>;
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<Brightness> for u8 { impl From<Brightness> for u8 {
fn from(brightness: Brightness) -> Self { fn from(brightness: Brightness) -> Self {
Self::from(&brightness)
}
}
impl From<&Brightness> for u8 {
fn from(brightness: &Brightness) -> Self {
brightness.0 brightness.0
} }
} }
@ -105,7 +118,7 @@ impl TryFrom<PrimitiveGrid<u8>> for BrightnessGrid {
let brightnesses = value let brightnesses = value
.iter() .iter()
.map(|b| Brightness::try_from(*b)) .map(|b| Brightness::try_from(*b))
.collect::<Result<Vec<Brightness>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
Ok(BrightnessGrid::load( Ok(BrightnessGrid::load(
value.width(), value.width(),
value.height(), value.height(),
@ -129,7 +142,7 @@ mod tests {
#[test] #[test]
fn brightness_from_u8() { fn brightness_from_u8() {
assert_eq!(Err(100), Brightness::try_from(100)); 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] #[test]
@ -155,4 +168,10 @@ mod tests {
assert_eq!(Brightness::MAX, Brightness::saturating_from(100)); assert_eq!(Brightness::MAX, Brightness::saturating_from(100));
assert_eq!(Brightness(5), Brightness::saturating_from(5)); 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]));
}
} }

View file

@ -0,0 +1,129 @@
use crate::primitive_grid::SeriesError;
use crate::{Grid, PrimitiveGrid};
/// A grid containing UTF-8 characters.
pub type CharGrid = PrimitiveGrid<char>;
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<String> {
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<String> {
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::<Vec<_>>().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::<Vec<_>>().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::<Vec<_>>();
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<String> 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::<String>()
.replace('\0', " ")
.trim_end()
.to_string()
})
.collect::<Vec<_>>()
.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);
}
}

View file

@ -1,11 +1,9 @@
use bitvec::prelude::BitVec;
use crate::{ use crate::{
command_code::CommandCode, command_code::CommandCode,
compression::into_decompressed, compression::into_decompressed,
packet::{Header, Packet}, packet::{Header, Packet},
Bitmap, Brightness, BrightnessGrid, CompressionCode, Cp437Grid, Origin, 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 /// 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. /// once the starting row is full, overwriting will continue on column 0.
/// ///
/// The contained [BitVec] is always uncompressed. /// 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. /// 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. /// once the starting row is full, overwriting will continue on column 0.
/// ///
/// The contained [BitVec] is always uncompressed. /// 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. /// 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. /// once the starting row is full, overwriting will continue on column 0.
/// ///
/// The contained [BitVec] is always uncompressed. /// 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. /// 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. /// once the starting row is full, overwriting will continue on column 0.
/// ///
/// The contained [BitVec] is always uncompressed. /// 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. /// 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]. /// Err values for [Command::try_from].
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, thiserror::Error)]
pub enum TryFromPacketError { pub enum TryFromPacketError {
/// the contained command code does not correspond to a known command /// 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), InvalidCommand(u16),
/// the expected payload size was n, but size m was found /// 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), UnexpectedPayloadSize(usize, usize),
/// Header fields not needed for the command have been used. /// Header fields not needed for the command have been used.
/// ///
/// Note that these commands would usually still work on the actual display. /// Note that these commands would usually still work on the actual display.
#[error("Header fields not needed for the command have been used")]
ExtraneousHeaderValues, ExtraneousHeaderValues,
/// The contained compression code is not known. This could be of disabled features. /// 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), InvalidCompressionCode(u16),
/// Decompression of the payload failed. This can be caused by corrupted packets. /// Decompression of the payload failed. This can be caused by corrupted packets.
#[error("The decompression of the payload failed")]
DecompressionFailed, DecompressionFailed,
/// The given brightness value is out of bounds /// The given brightness value is out of bounds
#[error("The given brightness value {0} is out of bounds.")]
InvalidBrightness(u8), InvalidBrightness(u8),
} }
@ -374,7 +378,7 @@ impl Command {
/// Helper method for Packets into `BitmapLinear*`-Commands /// Helper method for Packets into `BitmapLinear*`-Commands
fn packet_into_linear_bitmap( fn packet_into_linear_bitmap(
packet: Packet, packet: Packet,
) -> Result<(SpBitVec, CompressionCode), TryFromPacketError> { ) -> Result<(BitVec, CompressionCode), TryFromPacketError> {
let Packet { let Packet {
header: header:
Header { Header {

View file

@ -1,6 +1,5 @@
use std::fmt::Debug;
use crate::packet::Packet; use crate::packet::Packet;
use std::fmt::Debug;
/// A connection to the display. /// A connection to the display.
/// ///
@ -35,27 +34,24 @@ pub enum Connection {
/// [servicepoint-websocket-relay]: https://github.com/kaesaecracker/servicepoint-websocket-relay /// [servicepoint-websocket-relay]: https://github.com/kaesaecracker/servicepoint-websocket-relay
#[cfg(feature = "protocol_websocket")] #[cfg(feature = "protocol_websocket")]
WebSocket( WebSocket(
tungstenite::WebSocket< std::sync::Mutex<
tungstenite::stream::MaybeTlsStream<std::net::TcpStream>, tungstenite::WebSocket<
tungstenite::stream::MaybeTlsStream<std::net::TcpStream>,
>,
>, >,
), ),
/// A fake connection for testing that does not actually send anything. /// A fake connection for testing that does not actually send anything.
///
/// This variant allows immutable send.
Fake, 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 { pub enum SendError {
IoError(std::io::Error), #[error("IO error occurred while sending")]
IoError(#[from] std::io::Error),
#[cfg(feature = "protocol_websocket")] #[cfg(feature = "protocol_websocket")]
WebsocketError(tungstenite::Error), #[error("WebSocket error occurred while sending")]
WebsocketError(#[from] tungstenite::Error),
} }
impl Connection { impl Connection {
@ -96,7 +92,7 @@ impl Connection {
/// let uri = "ws://localhost:8080".parse().unwrap(); /// let uri = "ws://localhost:8080".parse().unwrap();
/// let mut connection = Connection::open_websocket(uri) /// let mut connection = Connection::open_websocket(uri)
/// .expect("could not connect"); /// .expect("could not connect");
/// connection.send_mut(Command::Clear) /// connection.send(Command::Clear)
/// .expect("send failed"); /// .expect("send failed");
/// ``` /// ```
#[cfg(feature = "protocol_websocket")] #[cfg(feature = "protocol_websocket")]
@ -111,25 +107,19 @@ impl Connection {
let request = ClientRequestBuilder::new(uri).into_client_request()?; let request = ClientRequestBuilder::new(uri).into_client_request()?;
let (sock, _) = connect(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. /// 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 /// # Arguments
/// ///
/// - `packet`: the packet-like to send /// - `packet`: the packet-like to send
/// ///
/// returns: true if packet was sent, otherwise false /// returns: true if packet was sent, otherwise false
/// ///
/// # Panics
///
/// If the connection does not support immutable send, e.g. for [Connection::WebSocket].
///
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
@ -150,59 +140,17 @@ impl Connection {
.map_err(SendError::IoError) .map_err(SendError::IoError)
.map(move |_| ()) // ignore Ok value .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<Packet>,
) -> Result<(), SendError> {
match self {
#[cfg(feature = "protocol_websocket")] #[cfg(feature = "protocol_websocket")]
Connection::WebSocket(socket) => { Connection::WebSocket(socket) => {
let packet = packet.into(); let mut socket = socket.lock().unwrap();
log::debug!("sending {packet:?}");
let data: Vec<u8> = packet.into();
socket socket
.send(tungstenite::Message::Binary(data)) .send(tungstenite::Message::Binary(data))
.map_err(SendError::WebsocketError) .map_err(SendError::WebsocketError)
} }
Connection::FakeMutableSend => { Connection::Fake => {
let packet = packet.into();
log::debug!("sending {packet:?}");
let data: Vec<u8> = packet.into();
let _ = data; let _ = data;
Ok(()) Ok(())
} }
_ => self.send(packet),
} }
} }
} }
@ -211,7 +159,9 @@ impl Drop for Connection {
fn drop(&mut self) { fn drop(&mut self) {
#[cfg(feature = "protocol_websocket")] #[cfg(feature = "protocol_websocket")]
if let Connection::WebSocket(sock) = self { 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(); let packet = Packet::try_from(data).unwrap();
Connection::Fake.send(packet).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()
}
} }

View file

@ -10,19 +10,14 @@ use std::collections::HashMap;
/// The encoding is currently not enforced. /// The encoding is currently not enforced.
pub type Cp437Grid = PrimitiveGrid<u8>; pub type Cp437Grid = PrimitiveGrid<u8>;
/// A grid containing UTF-8 characters. /// The error occurring when loading an invalid character
pub type CharGrid = PrimitiveGrid<char>; #[derive(Debug, PartialEq, thiserror::Error)]
#[error("The character {char:?} at position {index} is not a valid CP437 character")]
/// Errors that can occur when loading CP-437. pub struct InvalidCharError {
#[derive(Debug, PartialEq)] /// invalid character is at this position in input
pub enum Cp437LoadError { index: usize,
/// Invalid character in input prevented loading /// the invalid character
InvalidChar { char: char,
/// invalid character is at this position in input
index: usize,
/// the invalid character
char: char,
},
} }
impl Cp437Grid { impl Cp437Grid {
@ -36,7 +31,7 @@ impl Cp437Grid {
value: &str, value: &str,
width: usize, width: usize,
wrap: bool, wrap: bool,
) -> Result<Self, Cp437LoadError> { ) -> Result<Self, InvalidCharError> {
assert!(width > 0); assert!(width > 0);
assert!(!value.is_empty()); assert!(!value.is_empty());
@ -46,7 +41,7 @@ impl Cp437Grid {
for (index, char) in value.chars().enumerate() { for (index, char) in value.chars().enumerate() {
if !char.is_ascii() { if !char.is_ascii() {
return Err(Cp437LoadError::InvalidChar { index, char }); return Err(InvalidCharError { index, char });
} }
let is_lf = char == '\n'; let is_lf = char == '\n';
@ -92,6 +87,7 @@ pub use feature_cp437::*;
#[cfg(feature = "cp437")] #[cfg(feature = "cp437")]
mod feature_cp437 { mod feature_cp437 {
use super::*; use super::*;
use crate::CharGrid;
/// An array of 256 elements, mapping most of the CP437 values to UTF-8 characters /// An array of 256 elements, mapping most of the CP437 values to UTF-8 characters
/// ///
@ -99,7 +95,7 @@ mod feature_cp437 {
/// ///
/// See <https://en.wikipedia.org/wiki/Code_page_437#Character_set> /// See <https://en.wikipedia.org/wiki/Code_page_437#Character_set>
/// ///
/// Mostly 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] #[rustfmt::skip]
pub const CP437_TO_UTF8: [char; 256] = [ pub const CP437_TO_UTF8: [char; 256] = [
/* 0X */ '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '\n', '♂', '♀', '♪', '♫', '☼', /* 0X */ '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '\n', '♂', '♀', '♪', '♫', '☼',
@ -143,44 +139,9 @@ mod feature_cp437 {
} }
} }
impl From<&str> for CharGrid { impl From<CharGrid> for Cp437Grid {
fn from(value: &str) -> Self { fn from(value: CharGrid) -> Self {
let value = value.replace("\r\n", "\n"); Cp437Grid::from(&value)
let mut lines = value
.split('\n')
.map(move |line| line.trim_end())
.collect::<Vec<_>>();
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::<String>()
.replace('\0', " ")
.trim_end()
.to_string()
})
.collect::<Vec<_>>()
.join("\n")
} }
} }
@ -236,7 +197,7 @@ mod tests {
#[test] #[test]
fn load_ascii_invalid() { fn load_ascii_invalid() {
assert_eq!( assert_eq!(
Err(Cp437LoadError::InvalidChar { Err(InvalidCharError {
char: '🥶', char: '🥶',
index: 2 index: 2
}), }),
@ -249,6 +210,7 @@ mod tests {
#[cfg(feature = "cp437")] #[cfg(feature = "cp437")]
mod tests_feature_cp437 { mod tests_feature_cp437 {
use super::*; use super::*;
use crate::CharGrid;
#[test] #[test]
fn round_trip_cp437() { fn round_trip_cp437() {
@ -292,13 +254,4 @@ mod tests_feature_cp437 {
fn convert_invalid() { fn convert_invalid() {
assert_eq!(cp437_to_char(char_to_cp437('😜')), '?'); 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);
}
} }

View file

@ -38,23 +38,25 @@
use std::time::Duration; use std::time::Duration;
pub use bitvec; pub use bitvec;
use bitvec::prelude::{BitVec, Msb0};
pub use crate::bitmap::Bitmap; pub use crate::bitmap::Bitmap;
pub use crate::brightness::{Brightness, BrightnessGrid}; pub use crate::brightness::{Brightness, BrightnessGrid};
pub use crate::char_grid::CharGrid;
pub use crate::command::{Command, Offset}; pub use crate::command::{Command, Offset};
pub use crate::compression_code::CompressionCode; pub use crate::compression_code::CompressionCode;
pub use crate::connection::Connection; 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::data_ref::DataRef;
pub use crate::grid::Grid; pub use crate::grid::Grid;
pub use crate::origin::{Origin, Pixels, Tiles}; pub use crate::origin::{Origin, Pixels, Tiles};
pub use crate::primitive_grid::PrimitiveGrid; pub use crate::primitive_grid::{PrimitiveGrid, SeriesError};
type SpBitVec = BitVec<u8, Msb0>; /// An alias for the specific type of [bitvec::prelude::BitVec] used.
pub type BitVec = bitvec::prelude::BitVec<u8, bitvec::prelude::Msb0>;
mod bitmap; mod bitmap;
mod brightness; mod brightness;
mod char_grid;
mod command; mod command;
mod command_code; mod command_code;
mod compression; mod compression;

View file

@ -13,6 +13,27 @@ pub struct PrimitiveGrid<T: PrimitiveGridType> {
data: Vec<T>, data: Vec<T>,
} }
/// 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<T: PrimitiveGridType> PrimitiveGrid<T> { impl<T: PrimitiveGridType> PrimitiveGrid<T> {
/// Creates a new [PrimitiveGrid] with the specified dimensions. /// Creates a new [PrimitiveGrid] with the specified dimensions.
/// ///
@ -126,6 +147,8 @@ impl<T: PrimitiveGridType> PrimitiveGrid<T> {
/// let grid: BrightnessGrid = grid.map(Brightness::saturating_from); /// let grid: BrightnessGrid = grid.map(Brightness::saturating_from);
/// let command = Command::CharBrightness(Origin::ZERO, grid); /// let command = Command::CharBrightness(Origin::ZERO, grid);
/// ``` /// ```
/// [Brightness]: [crate::Brightness]
/// [Command]: [crate::Command]
pub fn map<TConverted, F>(&self, f: F) -> PrimitiveGrid<TConverted> pub fn map<TConverted, F>(&self, f: F) -> PrimitiveGrid<TConverted>
where where
TConverted: PrimitiveGridType, TConverted: PrimitiveGridType,
@ -138,6 +161,81 @@ impl<T: PrimitiveGridType> PrimitiveGrid<T> {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
PrimitiveGrid::load(self.width(), self.height(), &data) 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<Vec<T>> {
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<Vec<T>> {
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<T: PrimitiveGridType> Grid<T> for PrimitiveGrid<T> { impl<T: PrimitiveGridType> Grid<T> for PrimitiveGrid<T> {
@ -225,7 +323,7 @@ impl<'t, T: PrimitiveGridType> Iterator for IterRows<'t, T> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{DataRef, Grid, PrimitiveGrid}; use crate::{DataRef, Grid, PrimitiveGrid, SeriesError};
#[test] #[test]
fn fill() { fn fill() {
@ -347,4 +445,46 @@ mod tests {
assert_eq!(grid.get_optional(0, 0), Some(5)); assert_eq!(grid.get_optional(0, 0), Some(5));
assert_eq!(grid.get_optional(0, 8), None); 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
})
);
}
} }

View file

@ -17,7 +17,7 @@ crate-type = ["staticlib", "cdylib", "rlib"]
cbindgen = "0.27.0" cbindgen = "0.27.0"
[dependencies.servicepoint] [dependencies.servicepoint]
version = "0.10.0" version = "0.11.0"
path = "../servicepoint" path = "../servicepoint"
features = ["all_compressions"] features = ["all_compressions"]

View file

@ -144,6 +144,8 @@ typedef struct SPBrightnessGrid SPBrightnessGrid;
* sp_connection_send_command(connection, sp_command_clear()); * sp_connection_send_command(connection, sp_command_clear());
* sp_connection_send_command(connection, sp_command_brightness(5)); * sp_connection_send_command(connection, sp_command_brightness(5));
* ``` * ```
*
* [SPConnection]: [crate::SPConnection]
*/ */
typedef struct SPCommand SPCommand; typedef struct SPCommand SPCommand;
@ -266,6 +268,8 @@ void sp_bitmap_fill(SPBitmap *bitmap, bool value);
* - `bitmap` points to a valid [SPBitmap] * - `bitmap` points to a valid [SPBitmap]
* - `bitmap` is not used concurrently or after bitmap call * - `bitmap` is not used concurrently or after bitmap call
* - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] * - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand]
*
* [SPCommand]: [crate::SPCommand]
*/ */
void sp_bitmap_free(SPBitmap *bitmap); 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` points to a valid [SPBitVec]
* - `bit_vec` is not used concurrently or after this call * - `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]
*
* [SPCommand]: [crate::SPCommand]
*/ */
void sp_bitvec_free(SPBitVec *bit_vec); 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` points to a valid [SPBrightnessGrid]
* - `brightness_grid` is not used concurrently or after this call * - `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]
*
* [SPCommand]: [crate::SPCommand]
*/ */
void sp_brightness_grid_free(SPBrightnessGrid *brightness_grid); 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: * 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 * - `brightness_grid` is not written to or read from concurrently
*/ */
void sp_brightness_grid_set(SPBrightnessGrid *brightness_grid, 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. * 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 * # Panics
* *
@ -898,7 +906,7 @@ SPCommand *sp_command_bitmap_linear(size_t offset,
* *
* The passed [SPBitVec] gets consumed. * 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 * # Panics
* *
@ -929,7 +937,7 @@ SPCommand *sp_command_bitmap_linear_and(size_t offset,
* *
* The passed [SPBitVec] gets consumed. * 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 * # Panics
* *
@ -955,7 +963,7 @@ SPCommand *sp_command_bitmap_linear_or(size_t offset,
* *
* The passed [SPBitmap] gets consumed. * 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 * # Panics
* *
@ -987,7 +995,7 @@ SPCommand *sp_command_bitmap_linear_win(size_t x,
* *
* The passed [SPBitVec] gets consumed. * 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 * # Panics
* *
@ -1011,7 +1019,7 @@ SPCommand *sp_command_bitmap_linear_xor(size_t offset,
/** /**
* Set the brightness of all tiles to the same value. * 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 * # Panics
* *
@ -1031,7 +1039,7 @@ SPCommand *sp_command_brightness(uint8_t brightness);
* *
* The passed [SPBrightnessGrid] gets consumed. * 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 * # Panics
* *
@ -1055,7 +1063,7 @@ SPCommand *sp_command_char_brightness(size_t x,
* *
* Does not affect brightness. * 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 * # Examples
* *
@ -1097,7 +1105,7 @@ SPCommand *sp_command_clone(const SPCommand *command);
* *
* The passed [SPCp437Grid] gets consumed. * 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 * # Panics
* *
@ -1119,7 +1127,7 @@ SPCommand *sp_command_cp437_data(size_t x,
/** /**
* A yet-to-be-tested command. * 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 * # Safety
* *
@ -1159,7 +1167,7 @@ void sp_command_free(SPCommand *command);
* *
* Please do not send this in your normal program flow. * 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 * # 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` points to a valid [SPCp437Grid]
* - `cp437_grid` is not used concurrently or after cp437_grid call * - `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]
*
* [SPCommand]: [crate::SPCommand]
*/ */
void sp_cp437_grid_free(SPCp437Grid *cp437_grid); 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` points to a valid [SPBitVec]
* - `cp437_grid` is not written to or read from concurrently * - `cp437_grid` is not written to or read from concurrently
*
* [SPBitVec]: [crate::SPBitVec]
*/ */
void sp_cp437_grid_set(SPCp437Grid *cp437_grid, void sp_cp437_grid_set(SPCp437Grid *cp437_grid,
size_t x, size_t x,

View file

@ -124,6 +124,8 @@ pub unsafe extern "C" fn sp_bitmap_clone(
/// - `bitmap` points to a valid [SPBitmap] /// - `bitmap` points to a valid [SPBitmap]
/// - `bitmap` is not used concurrently or after bitmap call /// - `bitmap` is not used concurrently or after bitmap call
/// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] /// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand]
///
/// [SPCommand]: [crate::SPCommand]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) { pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) {
assert!(!bitmap.is_null()); assert!(!bitmap.is_null());

View file

@ -123,6 +123,8 @@ pub unsafe extern "C" fn sp_bitvec_clone(
/// - `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` 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]
///
/// [SPCommand]: [crate::SPCommand]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) { pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) {
assert!(!bit_vec.is_null()); assert!(!bit_vec.is_null());

View file

@ -133,6 +133,8 @@ pub unsafe extern "C" fn sp_brightness_grid_clone(
/// - `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` 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]
///
/// [SPCommand]: [crate::SPCommand]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_free( pub unsafe extern "C" fn sp_brightness_grid_free(
brightness_grid: *mut SPBrightnessGrid, brightness_grid: *mut SPBrightnessGrid,
@ -191,7 +193,7 @@ pub unsafe extern "C" fn sp_brightness_grid_get(
/// ///
/// The caller has to make sure that: /// 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 /// - `brightness_grid` is not written to or read from concurrently
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_set( pub unsafe extern "C" fn sp_brightness_grid_set(

View file

@ -23,6 +23,8 @@ use crate::{
/// sp_connection_send_command(connection, sp_command_clear()); /// sp_connection_send_command(connection, sp_command_clear());
/// sp_connection_send_command(connection, sp_command_brightness(5)); /// sp_connection_send_command(connection, sp_command_brightness(5));
/// ``` /// ```
///
/// [SPConnection]: [crate::SPConnection]
pub struct SPCommand(pub(crate) servicepoint::Command); pub struct SPCommand(pub(crate) servicepoint::Command);
impl Clone for SPCommand { impl Clone for SPCommand {
@ -90,7 +92,7 @@ pub unsafe extern "C" fn sp_command_clone(
/// ///
/// Does not affect brightness. /// 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 /// # Examples
/// ///
@ -114,7 +116,7 @@ pub unsafe extern "C" fn sp_command_clear() -> NonNull<SPCommand> {
/// ///
/// Please do not send this in your normal program flow. /// 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 /// # Safety
/// ///
@ -130,7 +132,7 @@ pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull<SPCommand> {
/// A yet-to-be-tested command. /// 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 /// # Safety
/// ///
@ -146,7 +148,7 @@ pub unsafe extern "C" fn sp_command_fade_out() -> NonNull<SPCommand> {
/// Set the brightness of all tiles to the same value. /// 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 /// # Panics
/// ///
@ -174,7 +176,7 @@ pub unsafe extern "C" fn sp_command_brightness(
/// ///
/// The passed [SPBrightnessGrid] gets consumed. /// 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 /// # Panics
/// ///
@ -211,7 +213,7 @@ pub unsafe extern "C" fn sp_command_char_brightness(
/// ///
/// The passed [SPBitVec] gets consumed. /// 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 /// # Panics
/// ///
@ -254,7 +256,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear(
/// ///
/// The passed [SPBitVec] gets consumed. /// 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 /// # Panics
/// ///
@ -297,7 +299,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_and(
/// ///
/// The passed [SPBitVec] gets consumed. /// 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 /// # Panics
/// ///
@ -340,7 +342,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_or(
/// ///
/// The passed [SPBitVec] gets consumed. /// 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 /// # Panics
/// ///
@ -378,7 +380,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
/// ///
/// The passed [SPCp437Grid] gets consumed. /// 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 /// # Panics
/// ///
@ -410,7 +412,7 @@ pub unsafe extern "C" fn sp_command_cp437_data(
/// ///
/// The passed [SPBitmap] gets consumed. /// 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 /// # Panics
/// ///

View file

@ -117,6 +117,8 @@ pub unsafe extern "C" fn sp_cp437_grid_clone(
/// - `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` 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]
///
/// [SPCommand]: [crate::SPCommand]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) { pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) {
assert!(!cp437_grid.is_null()); 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` points to a valid [SPBitVec]
/// - `cp437_grid` is not written to or read from concurrently /// - `cp437_grid` is not written to or read from concurrently
///
/// [SPBitVec]: [crate::SPBitVec]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sp_cp437_grid_set( pub unsafe extern "C" fn sp_cp437_grid_set(
cp437_grid: *mut SPCp437Grid, cp437_grid: *mut SPCp437Grid,

View file

@ -13,8 +13,8 @@ test = false
csbindgen = "1.9.3" csbindgen = "1.9.3"
[dependencies] [dependencies]
servicepoint_binding_c = { version = "0.10.0", path = "../servicepoint_binding_c" } servicepoint_binding_c = { version = "0.11.0", path = "../servicepoint_binding_c" }
servicepoint = { version = "0.10.0", path = "../servicepoint" } servicepoint = { version = "0.11.0", path = "../servicepoint" }
[lints] [lints]
workspace = true workspace = true

View file

@ -108,6 +108,8 @@ namespace ServicePoint.BindGen
/// - `bitmap` points to a valid [SPBitmap] /// - `bitmap` points to a valid [SPBitmap]
/// - `bitmap` is not used concurrently or after bitmap call /// - `bitmap` is not used concurrently or after bitmap call
/// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] /// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand]
///
/// [SPCommand]: [crate::SPCommand]
/// </summary> /// </summary>
[DllImport(__DllName, EntryPoint = "sp_bitmap_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [DllImport(__DllName, EntryPoint = "sp_bitmap_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_bitmap_free(Bitmap* bitmap); 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` points to a valid [SPBitVec]
/// - `bit_vec` is not used concurrently or after this call /// - `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]
///
/// [SPCommand]: [crate::SPCommand]
/// </summary> /// </summary>
[DllImport(__DllName, EntryPoint = "sp_bitvec_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [DllImport(__DllName, EntryPoint = "sp_bitvec_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_bitvec_free(BitVec* bit_vec); 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` points to a valid [SPBrightnessGrid]
/// - `brightness_grid` is not used concurrently or after this call /// - `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]
///
/// [SPCommand]: [crate::SPCommand]
/// </summary> /// </summary>
[DllImport(__DllName, EntryPoint = "sp_brightness_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [DllImport(__DllName, EntryPoint = "sp_brightness_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_brightness_grid_free(BrightnessGrid* brightness_grid); 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: /// 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 /// - `brightness_grid` is not written to or read from concurrently
/// </summary> /// </summary>
[DllImport(__DllName, EntryPoint = "sp_brightness_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [DllImport(__DllName, EntryPoint = "sp_brightness_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
@ -737,7 +743,7 @@ namespace ServicePoint.BindGen
/// ///
/// Does not affect brightness. /// 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 /// # Examples
/// ///
@ -760,7 +766,7 @@ namespace ServicePoint.BindGen
/// ///
/// Please do not send this in your normal program flow. /// 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 /// # Safety
/// ///
@ -775,7 +781,7 @@ namespace ServicePoint.BindGen
/// <summary> /// <summary>
/// A yet-to-be-tested command. /// 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 /// # Safety
/// ///
@ -790,7 +796,7 @@ namespace ServicePoint.BindGen
/// <summary> /// <summary>
/// Set the brightness of all tiles to the same value. /// 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 /// # Panics
/// ///
@ -811,7 +817,7 @@ namespace ServicePoint.BindGen
/// ///
/// The passed [SPBrightnessGrid] gets consumed. /// 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 /// # Panics
/// ///
@ -839,7 +845,7 @@ namespace ServicePoint.BindGen
/// ///
/// The passed [SPBitVec] gets consumed. /// 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 /// # Panics
/// ///
@ -869,7 +875,7 @@ namespace ServicePoint.BindGen
/// ///
/// The passed [SPBitVec] gets consumed. /// 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 /// # Panics
/// ///
@ -899,7 +905,7 @@ namespace ServicePoint.BindGen
/// ///
/// The passed [SPBitVec] gets consumed. /// 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 /// # Panics
/// ///
@ -929,7 +935,7 @@ namespace ServicePoint.BindGen
/// ///
/// The passed [SPBitVec] gets consumed. /// 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 /// # Panics
/// ///
@ -954,7 +960,7 @@ namespace ServicePoint.BindGen
/// ///
/// The passed [SPCp437Grid] gets consumed. /// 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 /// # Panics
/// ///
@ -977,7 +983,7 @@ namespace ServicePoint.BindGen
/// ///
/// The passed [SPBitmap] gets consumed. /// 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 /// # Panics
/// ///
@ -1178,6 +1184,8 @@ namespace ServicePoint.BindGen
/// - `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` 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]
///
/// [SPCommand]: [crate::SPCommand]
/// </summary> /// </summary>
[DllImport(__DllName, EntryPoint = "sp_cp437_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [DllImport(__DllName, EntryPoint = "sp_cp437_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_cp437_grid_free(Cp437Grid* cp437_grid); 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` points to a valid [SPBitVec]
/// - `cp437_grid` is not written to or read from concurrently /// - `cp437_grid` is not written to or read from concurrently
///
/// [SPBitVec]: [crate::SPBitVec]
/// </summary> /// </summary>
[DllImport(__DllName, EntryPoint = "sp_cp437_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [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); public static extern void sp_cp437_grid_set(Cp437Grid* cp437_grid, nuint x, nuint y, byte value);

View file

@ -11,7 +11,7 @@
<PropertyGroup> <PropertyGroup>
<PackageId>ServicePoint</PackageId> <PackageId>ServicePoint</PackageId>
<Version>0.10.0</Version> <Version>0.11.0</Version>
<Authors>Repository Authors</Authors> <Authors>Repository Authors</Authors>
<Company>None</Company> <Company>None</Company>
<Product>ServicePoint</Product> <Product>ServicePoint</Product>