mirror of
https://github.com/cccb/servicepoint.git
synced 2025-01-18 18:10:14 +01:00
Merge pull request #13 from cccb/fonts
More CP437, PrimitiveGrid::map, renamings
This commit is contained in:
commit
30d74ff07d
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -147,9 +147,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.1.29"
|
version = "1.1.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "58e804ac3194a48bb129643eb1d62fcc20d18c6b8c181704489353d13120bcd1"
|
checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -610,7 +610,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servicepoint"
|
name = "servicepoint"
|
||||||
version = "0.9.1"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"bzip2",
|
"bzip2",
|
||||||
|
@ -626,7 +626,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servicepoint_binding_c"
|
name = "servicepoint_binding_c"
|
||||||
version = "0.9.1"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cbindgen",
|
"cbindgen",
|
||||||
"servicepoint",
|
"servicepoint",
|
||||||
|
@ -634,7 +634,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servicepoint_binding_cs"
|
name = "servicepoint_binding_cs"
|
||||||
version = "0.9.1"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"csbindgen",
|
"csbindgen",
|
||||||
"servicepoint",
|
"servicepoint",
|
||||||
|
|
|
@ -6,7 +6,7 @@ members = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.9.1"
|
version = "0.10.0"
|
||||||
|
|
||||||
[workspace.lints.rust]
|
[workspace.lints.rust]
|
||||||
missing-docs = "warn"
|
missing-docs = "warn"
|
||||||
|
|
|
@ -17,7 +17,7 @@ cargo add servicepoint
|
||||||
or
|
or
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
servicepoint = "0.9.1"
|
servicepoint = "0.10.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
|
@ -6,16 +6,26 @@ use servicepoint::{CharGrid, Command, Connection, Cp437Grid, Origin};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[arg(short, long, default_value = "localhost:2342")]
|
#[arg(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
default_value = "localhost:2342",
|
||||||
|
help = "Address of the display"
|
||||||
|
)]
|
||||||
destination: String,
|
destination: String,
|
||||||
#[arg(short, long, num_args = 1.., value_delimiter = '\n')]
|
#[arg(short, long, num_args = 1.., value_delimiter = '\n',
|
||||||
|
help = "Text to send - specify multiple times for multiple lines")]
|
||||||
text: Vec<String>,
|
text: Vec<String>,
|
||||||
#[arg(short, long, default_value_t = true)]
|
#[arg(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
default_value_t = true,
|
||||||
|
help = "Clear screen before sending text"
|
||||||
|
)]
|
||||||
clear: bool,
|
clear: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// example: `cargo run -- --text "Hallo,
|
/// example: `cargo run -- --text "Hallo" --text "CCCB"`
|
||||||
/// CCCB"`
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut cli = Cli::parse();
|
let mut cli = Cli::parse();
|
||||||
if cli.text.is_empty() {
|
if cli.text.is_empty() {
|
||||||
|
@ -31,15 +41,11 @@ fn main() {
|
||||||
.expect("sending clear failed");
|
.expect("sending clear failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = cli.text.iter().fold(String::new(), move |str, line| {
|
let text = cli.text.join("\n");
|
||||||
let is_first = str.is_empty();
|
|
||||||
str + if is_first { "" } else { "\n" } + line
|
|
||||||
});
|
|
||||||
|
|
||||||
let grid = CharGrid::from(&*text);
|
let grid = CharGrid::from(&*text);
|
||||||
let cp437_grid = Cp437Grid::from(&grid);
|
let cp437_grid = Cp437Grid::from(&grid);
|
||||||
|
|
||||||
connection
|
connection
|
||||||
.send(Command::Cp437Data(Origin::new(0, 0), cp437_grid))
|
.send(Command::Cp437Data(Origin::ZERO, cp437_grid))
|
||||||
.expect("sending text failed");
|
.expect("sending text failed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,23 +15,24 @@ fn main() {
|
||||||
let connection = Connection::open(cli.destination)
|
let connection = Connection::open(cli.destination)
|
||||||
.expect("could not connect to display");
|
.expect("could not connect to display");
|
||||||
|
|
||||||
let mut pixels = PixelGrid::max_sized();
|
let mut pixels = Bitmap::max_sized();
|
||||||
pixels.fill(true);
|
pixels.fill(true);
|
||||||
|
|
||||||
let command = Command::BitmapLinearWin(
|
let command = Command::BitmapLinearWin(
|
||||||
Origin::new(0, 0),
|
Origin::ZERO,
|
||||||
pixels,
|
pixels,
|
||||||
CompressionCode::Uncompressed,
|
CompressionCode::Uncompressed,
|
||||||
);
|
);
|
||||||
connection.send(command).expect("send failed");
|
connection.send(command).expect("send failed");
|
||||||
|
|
||||||
let max_brightness = usize::from(u8::from(Brightness::MAX));
|
let max_brightness: u8 = Brightness::MAX.into();
|
||||||
let mut brightnesses = BrightnessGrid::new(TILE_WIDTH, TILE_HEIGHT);
|
let mut brightnesses = BrightnessGrid::new(TILE_WIDTH, TILE_HEIGHT);
|
||||||
for (index, byte) in brightnesses.data_ref_mut().iter_mut().enumerate() {
|
for (index, byte) in brightnesses.data_ref_mut().iter_mut().enumerate() {
|
||||||
*byte = Brightness::try_from((index % max_brightness) as u8).unwrap();
|
let level = index as u8 % max_brightness;
|
||||||
|
*byte = Brightness::try_from(level).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
connection
|
connection
|
||||||
.send(Command::CharBrightness(Origin::new(0, 0), brightnesses))
|
.send(Command::CharBrightness(Origin::ZERO, brightnesses))
|
||||||
.expect("send failed");
|
.expect("send failed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ fn main() {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let command = Command::BitmapLinearWin(
|
let command = Command::BitmapLinearWin(
|
||||||
Origin::new(0, 0),
|
Origin::ZERO,
|
||||||
field.clone(),
|
field.clone(),
|
||||||
CompressionCode::Lzma,
|
CompressionCode::Lzma,
|
||||||
);
|
);
|
||||||
|
@ -34,7 +34,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iteration(field: PixelGrid) -> PixelGrid {
|
fn iteration(field: Bitmap) -> Bitmap {
|
||||||
let mut next = field.clone();
|
let mut next = field.clone();
|
||||||
for x in 0..field.width() {
|
for x in 0..field.width() {
|
||||||
for y in 0..field.height() {
|
for y in 0..field.height() {
|
||||||
|
@ -51,7 +51,7 @@ fn iteration(field: PixelGrid) -> PixelGrid {
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_neighbors(field: &PixelGrid, x: i32, y: i32) -> i32 {
|
fn count_neighbors(field: &Bitmap, x: i32, y: i32) -> i32 {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
for nx in x - 1..=x + 1 {
|
for nx in x - 1..=x + 1 {
|
||||||
for ny in y - 1..=y + 1 {
|
for ny in y - 1..=y + 1 {
|
||||||
|
@ -78,8 +78,8 @@ fn count_neighbors(field: &PixelGrid, x: i32, y: i32) -> i32 {
|
||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_random_field(probability: f64) -> PixelGrid {
|
fn make_random_field(probability: f64) -> Bitmap {
|
||||||
let mut field = PixelGrid::max_sized();
|
let mut field = Bitmap::max_sized();
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let d = distributions::Bernoulli::new(probability).unwrap();
|
let d = distributions::Bernoulli::new(probability).unwrap();
|
||||||
for x in 0..field.width() {
|
for x in 0..field.width() {
|
||||||
|
|
|
@ -16,7 +16,7 @@ fn main() {
|
||||||
let connection = Connection::open(Cli::parse().destination)
|
let connection = Connection::open(Cli::parse().destination)
|
||||||
.expect("could not connect to display");
|
.expect("could not connect to display");
|
||||||
|
|
||||||
let mut pixels = PixelGrid::max_sized();
|
let mut pixels = Bitmap::max_sized();
|
||||||
for x_offset in 0..usize::MAX {
|
for x_offset in 0..usize::MAX {
|
||||||
pixels.fill(false);
|
pixels.fill(false);
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let command = Command::BitmapLinearWin(
|
let command = Command::BitmapLinearWin(
|
||||||
Origin::new(0, 0),
|
Origin::ZERO,
|
||||||
pixels.clone(),
|
pixels.clone(),
|
||||||
CompressionCode::Lzma,
|
CompressionCode::Lzma,
|
||||||
);
|
);
|
||||||
|
|
|
@ -28,11 +28,11 @@ fn main() {
|
||||||
|
|
||||||
// put all pixels in on state
|
// put all pixels in on state
|
||||||
if cli.enable_all {
|
if cli.enable_all {
|
||||||
let mut filled_grid = PixelGrid::max_sized();
|
let mut filled_grid = Bitmap::max_sized();
|
||||||
filled_grid.fill(true);
|
filled_grid.fill(true);
|
||||||
|
|
||||||
let command = BitmapLinearWin(
|
let command = BitmapLinearWin(
|
||||||
Origin::new(0, 0),
|
Origin::ZERO,
|
||||||
filled_grid,
|
filled_grid,
|
||||||
CompressionCode::Lzma,
|
CompressionCode::Lzma,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Example for how to use the WebSocket connection
|
//! Example for how to use the WebSocket connection
|
||||||
|
|
||||||
use servicepoint::{
|
use servicepoint::{
|
||||||
Command, CompressionCode, Connection, Grid, Origin, PixelGrid,
|
Bitmap, Command, CompressionCode, Connection, Grid, Origin,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -13,7 +13,7 @@ fn main() {
|
||||||
// use send_mut instead of send
|
// use send_mut instead of send
|
||||||
connection.send_mut(Command::Clear).unwrap();
|
connection.send_mut(Command::Clear).unwrap();
|
||||||
|
|
||||||
let mut pixels = PixelGrid::max_sized();
|
let mut pixels = Bitmap::max_sized();
|
||||||
pixels.fill(true);
|
pixels.fill(true);
|
||||||
|
|
||||||
// use send_mut instead of send
|
// use send_mut instead of send
|
||||||
|
|
|
@ -25,7 +25,7 @@ fn main() {
|
||||||
let connection = Connection::open(cli.destination)
|
let connection = Connection::open(cli.destination)
|
||||||
.expect("could not connect to display");
|
.expect("could not connect to display");
|
||||||
|
|
||||||
let mut enabled_pixels = PixelGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT);
|
let mut enabled_pixels = Bitmap::max_sized();
|
||||||
enabled_pixels.fill(true);
|
enabled_pixels.fill(true);
|
||||||
|
|
||||||
for x_offset in 0..PIXEL_WIDTH {
|
for x_offset in 0..PIXEL_WIDTH {
|
||||||
|
|
|
@ -6,21 +6,21 @@ use crate::{BitVec, DataRef, Grid, SpBitVec, 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)]
|
||||||
pub struct PixelGrid {
|
pub struct Bitmap {
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
bit_vec: SpBitVec,
|
bit_vec: SpBitVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PixelGrid {
|
impl Bitmap {
|
||||||
/// Creates a new [PixelGrid] with the specified dimensions.
|
/// Creates a new [Bitmap] with the specified dimensions.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `width`: size in pixels in x-direction
|
/// - `width`: size in pixels in x-direction
|
||||||
/// - `height`: size in pixels in y-direction
|
/// - `height`: size in pixels in y-direction
|
||||||
///
|
///
|
||||||
/// returns: [PixelGrid] initialized to all pixels off
|
/// returns: [Bitmap] initialized to all pixels off
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
@ -40,14 +40,14 @@ impl PixelGrid {
|
||||||
Self::new(PIXEL_WIDTH, PIXEL_HEIGHT)
|
Self::new(PIXEL_WIDTH, PIXEL_HEIGHT)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a [PixelGrid] with the specified dimensions from the provided data.
|
/// Loads a [Bitmap] with the specified dimensions from the provided data.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `width`: size in pixels in x-direction
|
/// - `width`: size in pixels in x-direction
|
||||||
/// - `height`: size in pixels in y-direction
|
/// - `height`: size in pixels in y-direction
|
||||||
///
|
///
|
||||||
/// returns: [PixelGrid] that contains a copy of the provided data
|
/// returns: [Bitmap] that contains a copy of the provided data
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
@ -64,12 +64,12 @@ impl PixelGrid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all cells in [PixelGrid].
|
/// Iterate over all cells in [Bitmap].
|
||||||
///
|
///
|
||||||
/// Order is equivalent to the following loop:
|
/// Order is equivalent to the following loop:
|
||||||
/// ```
|
/// ```
|
||||||
/// # use servicepoint::{PixelGrid, Grid};
|
/// # use servicepoint::{Bitmap, Grid};
|
||||||
/// # let grid = PixelGrid::new(8,2);
|
/// # let grid = Bitmap::new(8,2);
|
||||||
/// for y in 0..grid.height() {
|
/// for y in 0..grid.height() {
|
||||||
/// for x in 0..grid.width() {
|
/// for x in 0..grid.width() {
|
||||||
/// grid.get(x, y);
|
/// grid.get(x, y);
|
||||||
|
@ -80,12 +80,12 @@ impl PixelGrid {
|
||||||
self.bit_vec.iter().by_refs()
|
self.bit_vec.iter().by_refs()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all cells in [PixelGrid] mutably.
|
/// Iterate over all cells in [Bitmap] mutably.
|
||||||
///
|
///
|
||||||
/// Order is equivalent to the following loop:
|
/// Order is equivalent to the following loop:
|
||||||
/// ```
|
/// ```
|
||||||
/// # use servicepoint::{PixelGrid, Grid};
|
/// # use servicepoint::{Bitmap, Grid};
|
||||||
/// # let mut grid = PixelGrid::new(8,2);
|
/// # let mut grid = Bitmap::new(8,2);
|
||||||
/// # let value = false;
|
/// # let value = false;
|
||||||
/// for y in 0..grid.height() {
|
/// for y in 0..grid.height() {
|
||||||
/// for x in 0..grid.width() {
|
/// for x in 0..grid.width() {
|
||||||
|
@ -96,8 +96,8 @@ impl PixelGrid {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # use servicepoint::{PixelGrid, Grid};
|
/// # use servicepoint::{Bitmap, Grid};
|
||||||
/// # let mut grid = PixelGrid::new(8,2);
|
/// # let mut grid = Bitmap::new(8,2);
|
||||||
/// # let value = false;
|
/// # let value = false;
|
||||||
/// for (index, mut pixel) in grid.iter_mut().enumerate() {
|
/// for (index, mut pixel) in grid.iter_mut().enumerate() {
|
||||||
/// pixel.set(index % 2 == 0)
|
/// pixel.set(index % 2 == 0)
|
||||||
|
@ -107,17 +107,17 @@ impl PixelGrid {
|
||||||
self.bit_vec.iter_mut()
|
self.bit_vec.iter_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all rows in [PixelGrid] top to bottom.
|
/// Iterate over all rows in [Bitmap] top to bottom.
|
||||||
pub fn iter_rows(&self) -> IterRows {
|
pub fn iter_rows(&self) -> IterRows {
|
||||||
IterRows {
|
IterRows {
|
||||||
pixel_grid: self,
|
bitmap: self,
|
||||||
row: 0,
|
row: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Grid<bool> for PixelGrid {
|
impl Grid<bool> for Bitmap {
|
||||||
/// Sets the value of the specified position in the [PixelGrid].
|
/// Sets the value of the specified position in the [Bitmap].
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
|
@ -139,7 +139,7 @@ impl Grid<bool> for PixelGrid {
|
||||||
self.bit_vec[x + y * self.width]
|
self.bit_vec[x + y * self.width]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the state of all pixels in the [PixelGrid].
|
/// Sets the state of all pixels in the [Bitmap].
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
|
@ -158,7 +158,7 @@ impl Grid<bool> for PixelGrid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataRef<u8> for PixelGrid {
|
impl DataRef<u8> for Bitmap {
|
||||||
fn data_ref_mut(&mut self) -> &mut [u8] {
|
fn data_ref_mut(&mut self) -> &mut [u8] {
|
||||||
self.bit_vec.as_raw_mut_slice()
|
self.bit_vec.as_raw_mut_slice()
|
||||||
}
|
}
|
||||||
|
@ -168,15 +168,15 @@ impl DataRef<u8> for PixelGrid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PixelGrid> for Vec<u8> {
|
impl From<Bitmap> for Vec<u8> {
|
||||||
/// Turns a [PixelGrid] into the underlying [`Vec<u8>`].
|
/// Turns a [Bitmap] into the underlying [`Vec<u8>`].
|
||||||
fn from(value: PixelGrid) -> Self {
|
fn from(value: Bitmap) -> Self {
|
||||||
value.bit_vec.into()
|
value.bit_vec.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IterRows<'t> {
|
pub struct IterRows<'t> {
|
||||||
pixel_grid: &'t PixelGrid,
|
bitmap: &'t Bitmap,
|
||||||
row: usize,
|
row: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,24 +184,24 @@ impl<'t> Iterator for IterRows<'t> {
|
||||||
type Item = &'t BitSlice<u8, Msb0>;
|
type Item = &'t BitSlice<u8, Msb0>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.row >= self.pixel_grid.height {
|
if self.row >= self.bitmap.height {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let start = self.row * self.pixel_grid.width;
|
let start = self.row * self.bitmap.width;
|
||||||
let end = start + self.pixel_grid.width;
|
let end = start + self.bitmap.width;
|
||||||
self.row += 1;
|
self.row += 1;
|
||||||
Some(&self.pixel_grid.bit_vec[start..end])
|
Some(&self.bitmap.bit_vec[start..end])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{DataRef, Grid, PixelGrid};
|
use crate::{Bitmap, DataRef, Grid};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fill() {
|
fn fill() {
|
||||||
let mut grid = PixelGrid::new(8, 2);
|
let mut grid = Bitmap::new(8, 2);
|
||||||
assert_eq!(grid.data_ref(), [0x00, 0x00]);
|
assert_eq!(grid.data_ref(), [0x00, 0x00]);
|
||||||
|
|
||||||
grid.fill(true);
|
grid.fill(true);
|
||||||
|
@ -213,7 +213,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_set() {
|
fn get_set() {
|
||||||
let mut grid = PixelGrid::new(8, 2);
|
let mut grid = Bitmap::new(8, 2);
|
||||||
assert!(!grid.get(0, 0));
|
assert!(!grid.get(0, 0));
|
||||||
assert!(!grid.get(1, 1));
|
assert!(!grid.get(1, 1));
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load() {
|
fn load() {
|
||||||
let mut grid = PixelGrid::new(8, 3);
|
let mut grid = Bitmap::new(8, 3);
|
||||||
for x in 0..grid.width {
|
for x in 0..grid.width {
|
||||||
for y in 0..grid.height {
|
for y in 0..grid.height {
|
||||||
grid.set(x, y, (x + y) % 2 == 0);
|
grid.set(x, y, (x + y) % 2 == 0);
|
||||||
|
@ -239,33 +239,33 @@ mod tests {
|
||||||
|
|
||||||
let data: Vec<u8> = grid.into();
|
let data: Vec<u8> = grid.into();
|
||||||
|
|
||||||
let grid = PixelGrid::load(8, 3, &data);
|
let grid = Bitmap::load(8, 3, &data);
|
||||||
assert_eq!(grid.data_ref(), [0xAA, 0x55, 0xAA]);
|
assert_eq!(grid.data_ref(), [0xAA, 0x55, 0xAA]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn out_of_bounds_x() {
|
fn out_of_bounds_x() {
|
||||||
let vec = PixelGrid::new(8, 2);
|
let vec = Bitmap::new(8, 2);
|
||||||
vec.get(8, 1);
|
vec.get(8, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn out_of_bounds_y() {
|
fn out_of_bounds_y() {
|
||||||
let mut vec = PixelGrid::new(8, 2);
|
let mut vec = Bitmap::new(8, 2);
|
||||||
vec.set(1, 2, false);
|
vec.set(1, 2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iter() {
|
fn iter() {
|
||||||
let grid = PixelGrid::new(8, 2);
|
let grid = Bitmap::new(8, 2);
|
||||||
assert_eq!(16, grid.iter().count())
|
assert_eq!(16, grid.iter().count())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iter_rows() {
|
fn iter_rows() {
|
||||||
let grid = PixelGrid::load(8, 2, &[0x04, 0x40]);
|
let grid = Bitmap::load(8, 2, &[0x04, 0x40]);
|
||||||
let mut iter = grid.iter_rows();
|
let mut iter = grid.iter_rows();
|
||||||
|
|
||||||
assert_eq!(iter.next().unwrap().count_ones(), 1);
|
assert_eq!(iter.next().unwrap().count_ones(), 1);
|
||||||
|
@ -275,7 +275,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iter_mut() {
|
fn iter_mut() {
|
||||||
let mut grid = PixelGrid::new(8, 2);
|
let mut grid = Bitmap::new(8, 2);
|
||||||
for (index, mut pixel) in grid.iter_mut().enumerate() {
|
for (index, mut pixel) in grid.iter_mut().enumerate() {
|
||||||
pixel.set(index % 2 == 0);
|
pixel.set(index % 2 == 0);
|
||||||
}
|
}
|
||||||
|
@ -284,7 +284,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn data_ref_mut() {
|
fn data_ref_mut() {
|
||||||
let mut grid = PixelGrid::new(8, 2);
|
let mut grid = Bitmap::new(8, 2);
|
||||||
let data = grid.data_ref_mut();
|
let data = grid.data_ref_mut();
|
||||||
data[1] = 0x0F;
|
data[1] = 0x0F;
|
||||||
assert!(grid.get(7, 1));
|
assert!(grid.get(7, 1));
|
|
@ -60,6 +60,17 @@ impl Brightness {
|
||||||
pub const MAX: Brightness = Brightness(11);
|
pub const MAX: Brightness = Brightness(11);
|
||||||
/// lowest possible brightness value, 0
|
/// lowest possible brightness value, 0
|
||||||
pub const MIN: Brightness = Brightness(0);
|
pub const MIN: Brightness = Brightness(0);
|
||||||
|
|
||||||
|
/// Create a brightness value without returning an error for brightnesses above [Brightness::MAX].
|
||||||
|
///
|
||||||
|
/// returns: the specified value as a [Brightness], or [Brightness::MAX].
|
||||||
|
pub fn saturating_from(value: u8) -> Brightness {
|
||||||
|
if value > Brightness::MAX.into() {
|
||||||
|
Brightness::MAX
|
||||||
|
} else {
|
||||||
|
Brightness(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Brightness {
|
impl Default for Brightness {
|
||||||
|
@ -138,4 +149,10 @@ mod tests {
|
||||||
let actual = PrimitiveGrid::from(&grid);
|
let actual = PrimitiveGrid::from(&grid);
|
||||||
assert_eq!(actual.data_ref(), &[11, 0, 11, 11]);
|
assert_eq!(actual.data_ref(), &[11, 0, 11, 11]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn saturating_convert() {
|
||||||
|
assert_eq!(Brightness::MAX, Brightness::saturating_from(100));
|
||||||
|
assert_eq!(Brightness(5), Brightness::saturating_from(5));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
command_code::CommandCode,
|
command_code::CommandCode,
|
||||||
compression::into_decompressed,
|
compression::into_decompressed,
|
||||||
packet::{Header, Packet},
|
packet::{Header, Packet},
|
||||||
Brightness, BrightnessGrid, CompressionCode, Cp437Grid, Origin, PixelGrid,
|
Bitmap, Brightness, BrightnessGrid, CompressionCode, Cp437Grid, Origin,
|
||||||
Pixels, PrimitiveGrid, SpBitVec, Tiles, TILE_SIZE,
|
Pixels, PrimitiveGrid, SpBitVec, Tiles, TILE_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,12 +76,7 @@ pub enum Command {
|
||||||
|
|
||||||
/// Show text on the screen.
|
/// Show text on the screen.
|
||||||
///
|
///
|
||||||
/// The text is sent in the form of a 2D grid of characters.
|
/// The text is sent in the form of a 2D grid of [CP-437] encoded characters.
|
||||||
///
|
|
||||||
/// <div class="warning">
|
|
||||||
/// The library does not currently convert between UTF-8 and CP-437.
|
|
||||||
/// Because Rust expects UTF-8 strings, it might be necessary to only send ASCII for now.
|
|
||||||
/// </div>
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -100,6 +95,7 @@ pub enum Command {
|
||||||
/// let grid = Cp437Grid::load_ascii("Hello\nWorld", 5, false).unwrap();
|
/// let grid = Cp437Grid::load_ascii("Hello\nWorld", 5, false).unwrap();
|
||||||
/// connection.send(Command::Cp437Data(Origin::new(2, 2), grid)).unwrap();
|
/// connection.send(Command::Cp437Data(Origin::new(2, 2), grid)).unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
|
/// [CP-437]: https://en.wikipedia.org/wiki/Code_page_437
|
||||||
Cp437Data(Origin<Tiles>, Cp437Grid),
|
Cp437Data(Origin<Tiles>, Cp437Grid),
|
||||||
|
|
||||||
/// Overwrites a rectangular region of pixels.
|
/// Overwrites a rectangular region of pixels.
|
||||||
|
@ -109,23 +105,23 @@ pub enum Command {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
|
/// # use servicepoint::{Command, CompressionCode, Grid, Bitmap};
|
||||||
/// # let connection = servicepoint::Connection::Fake;
|
/// # let connection = servicepoint::Connection::Fake;
|
||||||
/// #
|
/// #
|
||||||
/// let mut pixels = PixelGrid::max_sized();
|
/// let mut pixels = Bitmap::max_sized();
|
||||||
/// // draw something to the pixels here
|
/// // draw something to the pixels here
|
||||||
/// # pixels.set(2, 5, true);
|
/// # pixels.set(2, 5, true);
|
||||||
///
|
///
|
||||||
/// // create command to send pixels
|
/// // create command to send pixels
|
||||||
/// let command = Command::BitmapLinearWin(
|
/// let command = Command::BitmapLinearWin(
|
||||||
/// servicepoint::Origin::new(0, 0),
|
/// servicepoint::Origin::ZERO,
|
||||||
/// pixels,
|
/// pixels,
|
||||||
/// CompressionCode::Uncompressed
|
/// CompressionCode::Uncompressed
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
/// connection.send(command).expect("send failed");
|
/// connection.send(command).expect("send failed");
|
||||||
/// ```
|
/// ```
|
||||||
BitmapLinearWin(Origin<Pixels>, PixelGrid, CompressionCode),
|
BitmapLinearWin(Origin<Pixels>, Bitmap, CompressionCode),
|
||||||
|
|
||||||
/// Set the brightness of all tiles to the same value.
|
/// Set the brightness of all tiles to the same value.
|
||||||
///
|
///
|
||||||
|
@ -217,9 +213,8 @@ pub enum Command {
|
||||||
BitmapLegacy,
|
BitmapLegacy,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// Err values for [Command::try_from].
|
/// Err values for [Command::try_from].
|
||||||
#[derive(PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
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
|
||||||
InvalidCommand(u16),
|
InvalidCommand(u16),
|
||||||
|
@ -342,7 +337,7 @@ impl Command {
|
||||||
|
|
||||||
Ok(Command::BitmapLinearWin(
|
Ok(Command::BitmapLinearWin(
|
||||||
Origin::new(tiles_x as usize * TILE_SIZE, pixels_y as usize),
|
Origin::new(tiles_x as usize * TILE_SIZE, pixels_y as usize),
|
||||||
PixelGrid::load(
|
Bitmap::load(
|
||||||
tile_w as usize * TILE_SIZE,
|
tile_w as usize * TILE_SIZE,
|
||||||
pixel_h as usize,
|
pixel_h as usize,
|
||||||
&payload,
|
&payload,
|
||||||
|
@ -376,7 +371,7 @@ impl Command {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper method for Packets into `BitMapLinear*`-Commands
|
/// Helper method for Packets into `BitmapLinear*`-Commands
|
||||||
fn packet_into_linear_bitmap(
|
fn packet_into_linear_bitmap(
|
||||||
packet: Packet,
|
packet: Packet,
|
||||||
) -> Result<(SpBitVec, CompressionCode), TryFromPacketError> {
|
) -> Result<(SpBitVec, CompressionCode), TryFromPacketError> {
|
||||||
|
@ -500,7 +495,8 @@ mod tests {
|
||||||
command_code::CommandCode,
|
command_code::CommandCode,
|
||||||
origin::Pixels,
|
origin::Pixels,
|
||||||
packet::{Header, Packet},
|
packet::{Header, Packet},
|
||||||
Brightness, Command, CompressionCode, Origin, PixelGrid, PrimitiveGrid,
|
Bitmap, Brightness, BrightnessGrid, Command, CompressionCode, Origin,
|
||||||
|
PrimitiveGrid,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn round_trip(original: Command) {
|
fn round_trip(original: Command) {
|
||||||
|
@ -592,8 +588,8 @@ mod tests {
|
||||||
compression,
|
compression,
|
||||||
));
|
));
|
||||||
round_trip(Command::BitmapLinearWin(
|
round_trip(Command::BitmapLinearWin(
|
||||||
Origin::new(0, 0),
|
Origin::ZERO,
|
||||||
PixelGrid::max_sized(),
|
Bitmap::max_sized(),
|
||||||
compression,
|
compression,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -718,7 +714,7 @@ mod tests {
|
||||||
for compression in all_compressions().to_owned() {
|
for compression in all_compressions().to_owned() {
|
||||||
let p: Packet = Command::BitmapLinearWin(
|
let p: Packet = Command::BitmapLinearWin(
|
||||||
Origin::new(16, 8),
|
Origin::new(16, 8),
|
||||||
PixelGrid::new(8, 8),
|
Bitmap::new(8, 8),
|
||||||
compression,
|
compression,
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
|
@ -907,4 +903,28 @@ mod tests {
|
||||||
Origin::new(1, 0) + Origin::new(3, 2)
|
Origin::new(1, 0) + Origin::new(3, 2)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn packet_into_char_brightness_invalid() {
|
||||||
|
let grid = BrightnessGrid::new(2, 2);
|
||||||
|
let command = Command::CharBrightness(Origin::ZERO, grid);
|
||||||
|
let mut packet: Packet = command.into();
|
||||||
|
let slot = packet.payload.get_mut(1).unwrap();
|
||||||
|
*slot = 23;
|
||||||
|
assert_eq!(
|
||||||
|
Command::try_from(packet),
|
||||||
|
Err(TryFromPacketError::InvalidBrightness(23))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn packet_into_brightness_invalid() {
|
||||||
|
let mut packet: Packet = Command::Brightness(Brightness::MAX).into();
|
||||||
|
let slot = packet.payload.get_mut(0).unwrap();
|
||||||
|
*slot = 42;
|
||||||
|
assert_eq!(
|
||||||
|
Command::try_from(packet),
|
||||||
|
Err(TryFromPacketError::InvalidBrightness(42))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use servicepoint::{Command, CompressionCode, Origin, PixelGrid};
|
/// # use servicepoint::{Command, CompressionCode, Origin, Bitmap};
|
||||||
/// // create command without payload compression
|
/// // create command without payload compression
|
||||||
/// # let pixels = PixelGrid::max_sized();
|
/// # let pixels = Bitmap::max_sized();
|
||||||
/// _ = Command::BitmapLinearWin(Origin::new(0, 0), pixels, CompressionCode::Uncompressed);
|
/// _ = Command::BitmapLinearWin(Origin::ZERO, pixels, CompressionCode::Uncompressed);
|
||||||
///
|
///
|
||||||
/// // create command with payload compressed with lzma and appropriate header flags
|
/// // create command with payload compressed with lzma and appropriate header flags
|
||||||
/// # let pixels = PixelGrid::max_sized();
|
/// # let pixels = Bitmap::max_sized();
|
||||||
/// _ = Command::BitmapLinearWin(Origin::new(0, 0), pixels, CompressionCode::Lzma);
|
/// _ = Command::BitmapLinearWin(Origin::ZERO, pixels, CompressionCode::Lzma);
|
||||||
/// ```
|
/// ```
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use crate::cp437::Cp437LoadError::InvalidChar;
|
//! Conversion between UTF-8 and CP-437.
|
||||||
|
//!
|
||||||
|
//! Most of the functionality is only available with feature "cp437" enabled.
|
||||||
|
|
||||||
use crate::{Grid, PrimitiveGrid};
|
use crate::{Grid, PrimitiveGrid};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
@ -10,9 +13,16 @@ pub type Cp437Grid = PrimitiveGrid<u8>;
|
||||||
/// A grid containing UTF-8 characters.
|
/// A grid containing UTF-8 characters.
|
||||||
pub type CharGrid = PrimitiveGrid<char>;
|
pub type CharGrid = PrimitiveGrid<char>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Errors that can occur when loading CP-437.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Cp437LoadError {
|
pub enum Cp437LoadError {
|
||||||
InvalidChar { index: usize, char: char },
|
/// Invalid character in input prevented loading
|
||||||
|
InvalidChar {
|
||||||
|
/// invalid character is at this position in input
|
||||||
|
index: usize,
|
||||||
|
/// the invalid character
|
||||||
|
char: char,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cp437Grid {
|
impl Cp437Grid {
|
||||||
|
@ -36,7 +46,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(InvalidChar { index, char });
|
return Err(Cp437LoadError::InvalidChar { index, char });
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_lf = char == '\n';
|
let is_lf = char == '\n';
|
||||||
|
@ -85,21 +95,15 @@ mod feature_cp437 {
|
||||||
|
|
||||||
/// An array of 256 elements, mapping most of the CP437 values to UTF-8 characters
|
/// An array of 256 elements, mapping most of the CP437 values to UTF-8 characters
|
||||||
///
|
///
|
||||||
/// Mostly follows CP437, except for:
|
/// Mostly follows CP437, except 0x0A, which is kept for use as line ending.
|
||||||
/// * 0x0A & 0x0D are kept for use as line endings.
|
|
||||||
/// * 0x1A is used for SAUCE.
|
|
||||||
/// * 0x1B is used for ANSI escape sequences.
|
|
||||||
///
|
|
||||||
/// These exclusions should be fine since most programs can't even use them
|
|
||||||
/// without issues. And this makes rendering simpler too.
|
|
||||||
///
|
///
|
||||||
/// See <https://en.wikipedia.org/wiki/Code_page_437#Character_set>
|
/// See <https://en.wikipedia.org/wiki/Code_page_437#Character_set>
|
||||||
///
|
///
|
||||||
/// 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]
|
||||||
const CP437_TO_UTF8: [char; 256] = [
|
pub const CP437_TO_UTF8: [char; 256] = [
|
||||||
/* 0X */ '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '\n', '♂', '♀', '\r', '♫', '☼',
|
/* 0X */ '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '\n', '♂', '♀', '♪', '♫', '☼',
|
||||||
/* 1X */ '►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '', '', '∟', '↔', '▲', '▼',
|
/* 1X */ '►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '→', '←', '∟', '↔', '▲', '▼',
|
||||||
/* 2X */ ' ', '!', '"', '#', '$', '%', '&', '\'','(', ')', '*', '+', ',', '-', '.', '/',
|
/* 2X */ ' ', '!', '"', '#', '$', '%', '&', '\'','(', ')', '*', '+', ',', '-', '.', '/',
|
||||||
/* 3X */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
/* 3X */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
||||||
/* 4X */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
/* 4X */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||||
|
@ -116,7 +120,7 @@ mod feature_cp437 {
|
||||||
/* FX */ '≡', '±', '≥', '≤', '⌠', '⌡', '÷', '≈', '°', '∙', '·', '√', 'ⁿ', '²', '■', ' ',
|
/* FX */ '≡', '±', '≥', '≤', '⌠', '⌡', '÷', '≈', '°', '∙', '·', '√', 'ⁿ', '²', '■', ' ',
|
||||||
];
|
];
|
||||||
|
|
||||||
const UTF8_TO_CP437: once_cell::sync::Lazy<HashMap<char, u8>> =
|
static UTF8_TO_CP437: once_cell::sync::Lazy<HashMap<char, u8>> =
|
||||||
once_cell::sync::Lazy::new(|| {
|
once_cell::sync::Lazy::new(|| {
|
||||||
let pairs = CP437_TO_UTF8
|
let pairs = CP437_TO_UTF8
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -125,48 +129,34 @@ mod feature_cp437 {
|
||||||
HashMap::from_iter(pairs)
|
HashMap::from_iter(pairs)
|
||||||
});
|
});
|
||||||
|
|
||||||
const MISSING_CHAR_CP437: u8 = 0x3F;
|
const MISSING_CHAR_CP437: u8 = 0x3F; // '?'
|
||||||
|
|
||||||
impl From<&Cp437Grid> for CharGrid {
|
impl From<&Cp437Grid> for CharGrid {
|
||||||
fn from(value: &Cp437Grid) -> Self {
|
fn from(value: &Cp437Grid) -> Self {
|
||||||
let mut grid = Self::new(value.width(), value.height());
|
value.map(cp437_to_char)
|
||||||
|
|
||||||
for y in 0..grid.height() {
|
|
||||||
for x in 0..grid.width() {
|
|
||||||
let converted = CP437_TO_UTF8[value.get(x, y) as usize];
|
|
||||||
grid.set(x, y, converted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
grid
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&CharGrid> for Cp437Grid {
|
impl From<&CharGrid> for Cp437Grid {
|
||||||
fn from(value: &CharGrid) -> Self {
|
fn from(value: &CharGrid) -> Self {
|
||||||
let mut grid = Self::new(value.width(), value.height());
|
value.map(char_to_cp437)
|
||||||
|
|
||||||
for y in 0..grid.height() {
|
|
||||||
for x in 0..grid.width() {
|
|
||||||
let char = value.get(x, y);
|
|
||||||
let converted = *UTF8_TO_CP437
|
|
||||||
.get(&char)
|
|
||||||
.unwrap_or(&MISSING_CHAR_CP437);
|
|
||||||
grid.set(x, y, converted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
grid
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for CharGrid {
|
impl From<&str> for CharGrid {
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: &str) -> Self {
|
||||||
let value = value.replace("\r\n", "\n");
|
let value = value.replace("\r\n", "\n");
|
||||||
let lines = value.split('\n').collect::<Vec<_>>();
|
let mut lines = value
|
||||||
|
.split('\n')
|
||||||
|
.map(move |line| line.trim_end())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let width =
|
let width =
|
||||||
lines.iter().fold(0, move |a, x| std::cmp::max(a, x.len()));
|
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());
|
let mut grid = Self::new(width, lines.len());
|
||||||
for (y, line) in lines.iter().enumerate() {
|
for (y, line) in lines.iter().enumerate() {
|
||||||
for (x, char) in line.chars().enumerate() {
|
for (x, char) in line.chars().enumerate() {
|
||||||
|
@ -177,6 +167,44 @@ mod feature_cp437 {
|
||||||
grid
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the provided bytes to UTF-8.
|
||||||
|
pub fn cp437_to_str(cp437: &[u8]) -> String {
|
||||||
|
cp437.iter().map(move |char| cp437_to_char(*char)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a single CP-437 character to UTF-8.
|
||||||
|
pub fn cp437_to_char(cp437: u8) -> char {
|
||||||
|
CP437_TO_UTF8[cp437 as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the provided text to CP-437 bytes.
|
||||||
|
///
|
||||||
|
/// Characters that are not available are mapped to '?'.
|
||||||
|
pub fn str_to_cp437(utf8: &str) -> Vec<u8> {
|
||||||
|
utf8.chars().map(char_to_cp437).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a single UTF-8 character to CP-437.
|
||||||
|
pub fn char_to_cp437(utf8: char) -> u8 {
|
||||||
|
*UTF8_TO_CP437.get(&utf8).unwrap_or(&MISSING_CHAR_CP437)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -204,12 +232,23 @@ mod tests {
|
||||||
// line break will be added
|
// line break will be added
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_ascii_invalid() {
|
||||||
|
assert_eq!(
|
||||||
|
Err(Cp437LoadError::InvalidChar {
|
||||||
|
char: '🥶',
|
||||||
|
index: 2
|
||||||
|
}),
|
||||||
|
Cp437Grid::load_ascii("?#🥶42", 3, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[cfg(feature = "cp437")]
|
#[cfg(feature = "cp437")]
|
||||||
mod tests_feature_cp437 {
|
mod tests_feature_cp437 {
|
||||||
use crate::{CharGrid, Cp437Grid};
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn round_trip_cp437() {
|
fn round_trip_cp437() {
|
||||||
|
@ -218,4 +257,48 @@ mod tests_feature_cp437 {
|
||||||
let actual = CharGrid::from(&cp437);
|
let actual = CharGrid::from(&cp437);
|
||||||
assert_eq!(actual, utf8);
|
assert_eq!(actual, utf8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_str() {
|
||||||
|
// test text from https://int10h.org/oldschool-pc-fonts/fontlist/font?ibm_bios
|
||||||
|
let utf8 = r#"A quick brown fox jumps over the lazy dog.
|
||||||
|
0123456789 ¿?¡!`'"., <>()[]{} &@%*^#$\/
|
||||||
|
|
||||||
|
* Wieniläinen sioux'ta puhuva ökyzombie diggaa Åsan roquefort-tacoja.
|
||||||
|
* Ça me fait peur de fêter noël là, sur cette île bizarroïde où une mère et sa môme essaient de me tuer avec un gâteau à la cigüe brûlé.
|
||||||
|
* Zwölf Boxkämpfer jagten Eva quer über den Sylter Deich.
|
||||||
|
* El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.
|
||||||
|
|
||||||
|
┌─┬─┐ ╔═╦═╗ ╒═╤═╕ ╓─╥─╖
|
||||||
|
│ │ │ ║ ║ ║ │ │ │ ║ ║ ║
|
||||||
|
├─┼─┤ ╠═╬═╣ ╞═╪═╡ ╟─╫─╢
|
||||||
|
└─┴─┘ ╚═╩═╝ ╘═╧═╛ ╙─╨─╜
|
||||||
|
|
||||||
|
░░░░░ ▐▀█▀▌ .·∙•○°○•∙·.
|
||||||
|
▒▒▒▒▒ ▐ █ ▌ ☺☻ ♥♦♣♠ ♪♫☼
|
||||||
|
▓▓▓▓▓ ▐▀█▀▌ $ ¢ £ ¥ ₧
|
||||||
|
█████ ▐▄█▄▌ ◄►▲▼ ←→↑↓↕↨
|
||||||
|
|
||||||
|
⌠
|
||||||
|
│dx ≡ Σ √x²ⁿ·δx
|
||||||
|
⌡"#;
|
||||||
|
|
||||||
|
let cp437 = str_to_cp437(utf8);
|
||||||
|
let actual = cp437_to_str(&*cp437);
|
||||||
|
assert_eq!(utf8, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_invalid() {
|
||||||
|
assert_eq!(cp437_to_char(char_to_cp437('😜')), '?');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_to_char_grid() {
|
||||||
|
let original = "Hello\r\nWorld!\n...\n";
|
||||||
|
let grid = CharGrid::from(original);
|
||||||
|
assert_eq!(3, grid.height());
|
||||||
|
let actual = String::from(&grid);
|
||||||
|
assert_eq!("Hello\nWorld!\n...", actual);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,15 +76,9 @@ pub trait Grid<T> {
|
||||||
///
|
///
|
||||||
/// When the specified position is out of bounds for this grid.
|
/// When the specified position is out of bounds for this grid.
|
||||||
fn assert_in_bounds(&self, x: usize, y: usize) {
|
fn assert_in_bounds(&self, x: usize, y: usize) {
|
||||||
assert!(
|
let width = self.width();
|
||||||
x < self.width(),
|
assert!(x < width, "cannot access index [{x}, {y}] because x is outside of bounds [0..{width})");
|
||||||
"cannot access index [{x}, {y}] because x is outside of bounds 0..{}",
|
let height = self.height();
|
||||||
self.width() - 1
|
assert!(y < height, "cannot access index [{x}, {y}] because x is outside of bounds [0..{height})");
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
y < self.height(),
|
|
||||||
"cannot access index [{x}, {y}] because y is outside of bounds 0..{}",
|
|
||||||
self.height() - 1
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//! # Examples
|
//! # Examples
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
|
//! use servicepoint::{Command, CompressionCode, Grid, Bitmap};
|
||||||
//!
|
//!
|
||||||
//! let connection = servicepoint::Connection::open("127.0.0.1:2342")
|
//! let connection = servicepoint::Connection::open("127.0.0.1:2342")
|
||||||
//! .expect("connection failed");
|
//! .expect("connection failed");
|
||||||
|
@ -18,15 +18,15 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! # use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
|
//! # use servicepoint::{Command, CompressionCode, Grid, Bitmap};
|
||||||
//! # let connection = servicepoint::Connection::open("127.0.0.1:2342").expect("connection failed");
|
//! # let connection = servicepoint::Connection::open("127.0.0.1:2342").expect("connection failed");
|
||||||
//! // turn on all pixels in a grid
|
//! // turn on all pixels in a grid
|
||||||
//! let mut pixels = PixelGrid::max_sized();
|
//! let mut pixels = Bitmap::max_sized();
|
||||||
//! pixels.fill(true);
|
//! pixels.fill(true);
|
||||||
//!
|
//!
|
||||||
//! // create command to send pixels
|
//! // create command to send pixels
|
||||||
//! let command = Command::BitmapLinearWin(
|
//! let command = Command::BitmapLinearWin(
|
||||||
//! servicepoint::Origin::new(0, 0),
|
//! servicepoint::Origin::ZERO,
|
||||||
//! pixels,
|
//! pixels,
|
||||||
//! CompressionCode::Uncompressed
|
//! CompressionCode::Uncompressed
|
||||||
//! );
|
//! );
|
||||||
|
@ -40,6 +40,7 @@ use std::time::Duration;
|
||||||
pub use bitvec;
|
pub use bitvec;
|
||||||
use bitvec::prelude::{BitVec, Msb0};
|
use bitvec::prelude::{BitVec, Msb0};
|
||||||
|
|
||||||
|
pub use crate::bitmap::Bitmap;
|
||||||
pub use crate::brightness::{Brightness, BrightnessGrid};
|
pub use crate::brightness::{Brightness, BrightnessGrid};
|
||||||
pub use crate::command::{Command, Offset};
|
pub use crate::command::{Command, Offset};
|
||||||
pub use crate::compression_code::CompressionCode;
|
pub use crate::compression_code::CompressionCode;
|
||||||
|
@ -48,23 +49,22 @@ pub use crate::cp437::{CharGrid, Cp437Grid};
|
||||||
pub use crate::data_ref::DataRef;
|
pub use crate::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::pixel_grid::PixelGrid;
|
|
||||||
pub use crate::primitive_grid::PrimitiveGrid;
|
pub use crate::primitive_grid::PrimitiveGrid;
|
||||||
|
|
||||||
type SpBitVec = BitVec<u8, Msb0>;
|
type SpBitVec = BitVec<u8, Msb0>;
|
||||||
|
|
||||||
|
mod bitmap;
|
||||||
mod brightness;
|
mod brightness;
|
||||||
mod command;
|
mod command;
|
||||||
mod command_code;
|
mod command_code;
|
||||||
mod compression;
|
mod compression;
|
||||||
mod compression_code;
|
mod compression_code;
|
||||||
mod connection;
|
mod connection;
|
||||||
mod cp437;
|
pub mod cp437;
|
||||||
mod data_ref;
|
mod data_ref;
|
||||||
mod grid;
|
mod grid;
|
||||||
mod origin;
|
mod origin;
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
mod pixel_grid;
|
|
||||||
mod primitive_grid;
|
mod primitive_grid;
|
||||||
|
|
||||||
/// size of a single tile in one dimension
|
/// size of a single tile in one dimension
|
||||||
|
@ -95,8 +95,8 @@ pub const TILE_HEIGHT: usize = 20;
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid};
|
/// # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, Bitmap};
|
||||||
/// let grid = PixelGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT);
|
/// let grid = Bitmap::new(PIXEL_WIDTH, PIXEL_HEIGHT);
|
||||||
/// ```
|
/// ```
|
||||||
pub const PIXEL_WIDTH: usize = TILE_WIDTH * TILE_SIZE;
|
pub const PIXEL_WIDTH: usize = TILE_WIDTH * TILE_SIZE;
|
||||||
|
|
||||||
|
@ -105,8 +105,8 @@ pub const PIXEL_WIDTH: usize = TILE_WIDTH * TILE_SIZE;
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid};
|
/// # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, Bitmap};
|
||||||
/// let grid = PixelGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT);
|
/// let grid = Bitmap::new(PIXEL_WIDTH, PIXEL_HEIGHT);
|
||||||
/// ```
|
/// ```
|
||||||
pub const PIXEL_HEIGHT: usize = TILE_HEIGHT * TILE_SIZE;
|
pub const PIXEL_HEIGHT: usize = TILE_HEIGHT * TILE_SIZE;
|
||||||
|
|
||||||
|
@ -119,10 +119,10 @@ pub const PIXEL_COUNT: usize = PIXEL_WIDTH * PIXEL_HEIGHT;
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use std::time::Instant;
|
/// # use std::time::Instant;
|
||||||
/// # use servicepoint::{Command, CompressionCode, FRAME_PACING, Origin, PixelGrid};
|
/// # use servicepoint::{Command, CompressionCode, FRAME_PACING, Origin, Bitmap};
|
||||||
/// # let connection = servicepoint::Connection::open("172.23.42.29:2342")
|
/// # let connection = servicepoint::Connection::open("172.23.42.29:2342")
|
||||||
/// # .expect("connection failed");
|
/// # .expect("connection failed");
|
||||||
/// # let pixels = PixelGrid::max_sized();
|
/// # let pixels = Bitmap::max_sized();
|
||||||
/// loop {
|
/// loop {
|
||||||
/// let start = Instant::now();
|
/// let start = Instant::now();
|
||||||
///
|
///
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub struct Origin<Unit: DisplayUnit> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Unit: DisplayUnit> Origin<Unit> {
|
impl<Unit: DisplayUnit> Origin<Unit> {
|
||||||
/// Top-left. Equivalent to `Origin::new(0, 0)`.
|
/// Top-left. Equivalent to `Origin::ZERO`.
|
||||||
pub const ZERO: Self = Self {
|
pub const ZERO: Self = Self {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
|
|
|
@ -27,8 +27,8 @@ use std::mem::size_of;
|
||||||
|
|
||||||
use crate::compression::into_compressed;
|
use crate::compression::into_compressed;
|
||||||
use crate::{
|
use crate::{
|
||||||
command_code::CommandCode, Command, CompressionCode, Grid, Offset, Origin,
|
command_code::CommandCode, Bitmap, Command, CompressionCode, Grid, Offset,
|
||||||
PixelGrid, Pixels, Tiles, TILE_SIZE,
|
Origin, Pixels, Tiles, TILE_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A raw header.
|
/// A raw header.
|
||||||
|
@ -214,7 +214,7 @@ impl From<Command> for Packet {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Packet {
|
impl Packet {
|
||||||
/// Helper method for `BitMapLinear*`-Commands into [Packet]
|
/// Helper method for `BitmapLinear*`-Commands into [Packet]
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
fn bitmap_linear_into_packet(
|
fn bitmap_linear_into_packet(
|
||||||
command: CommandCode,
|
command: CommandCode,
|
||||||
|
@ -239,7 +239,7 @@ impl Packet {
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
fn bitmap_win_into_packet(
|
fn bitmap_win_into_packet(
|
||||||
origin: Origin<Pixels>,
|
origin: Origin<Pixels>,
|
||||||
pixels: PixelGrid,
|
pixels: Bitmap,
|
||||||
compression: CompressionCode,
|
compression: CompressionCode,
|
||||||
) -> Packet {
|
) -> Packet {
|
||||||
debug_assert_eq!(origin.x % 8, 0);
|
debug_assert_eq!(origin.x % 8, 0);
|
||||||
|
|
|
@ -110,6 +110,34 @@ impl<T: PrimitiveGridType> PrimitiveGrid<T> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert between PrimitiveGrid types.
|
||||||
|
///
|
||||||
|
/// See also [Iterator::map].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Use logic written for u8s and then convert to [Brightness] values for sending in a [Command].
|
||||||
|
/// ```
|
||||||
|
/// # fn foo(grid: &mut PrimitiveGrid<u8>) {}
|
||||||
|
/// # use servicepoint::{Brightness, BrightnessGrid, Command, Origin, PrimitiveGrid, TILE_HEIGHT, TILE_WIDTH};
|
||||||
|
/// let mut grid: PrimitiveGrid<u8> = PrimitiveGrid::new(TILE_WIDTH, TILE_HEIGHT);
|
||||||
|
/// foo(&mut grid);
|
||||||
|
/// let grid: BrightnessGrid = grid.map(Brightness::saturating_from);
|
||||||
|
/// let command = Command::CharBrightness(Origin::ZERO, grid);
|
||||||
|
/// ```
|
||||||
|
pub fn map<TConverted, F>(&self, f: F) -> PrimitiveGrid<TConverted>
|
||||||
|
where
|
||||||
|
TConverted: PrimitiveGridType,
|
||||||
|
F: Fn(T) -> TConverted,
|
||||||
|
{
|
||||||
|
let data = self
|
||||||
|
.data_ref()
|
||||||
|
.iter()
|
||||||
|
.map(|elem| f(*elem))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
PrimitiveGrid::load(self.width(), self.height(), &data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PrimitiveGridType> Grid<T> for PrimitiveGrid<T> {
|
impl<T: PrimitiveGridType> Grid<T> for PrimitiveGrid<T> {
|
||||||
|
|
|
@ -17,7 +17,7 @@ crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
cbindgen = "0.27.0"
|
cbindgen = "0.27.0"
|
||||||
|
|
||||||
[dependencies.servicepoint]
|
[dependencies.servicepoint]
|
||||||
version = "0.9.1"
|
version = "0.10.0"
|
||||||
path = "../servicepoint"
|
path = "../servicepoint"
|
||||||
features = ["all_compressions"]
|
features = ["all_compressions"]
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ int main(void) {
|
||||||
if (connection == NULL)
|
if (connection == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
SPPixelGrid *pixels = sp_pixel_grid_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
|
SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
|
||||||
sp_pixel_grid_fill(pixels, true);
|
sp_bitmap_fill(pixels, true);
|
||||||
|
|
||||||
SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
|
SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
|
||||||
while (sp_connection_send_command(connection, sp_command_clone(command)));
|
while (sp_connection_send_command(connection, sp_command_clone(command)));
|
||||||
|
|
|
@ -16,7 +16,7 @@ line_endings = "LF"
|
||||||
|
|
||||||
############################# Codegen Options ##################################
|
############################# Codegen Options ##################################
|
||||||
|
|
||||||
style = "both"
|
style = "type"
|
||||||
usize_is_size_t = true
|
usize_is_size_t = true
|
||||||
|
|
||||||
# this is needed because otherwise the order in the C# bindings is different on different machines
|
# this is needed because otherwise the order in the C# bindings is different on different machines
|
||||||
|
@ -31,3 +31,6 @@ all_features = true
|
||||||
[export]
|
[export]
|
||||||
include = []
|
include = []
|
||||||
exclude = []
|
exclude = []
|
||||||
|
|
||||||
|
[enum]
|
||||||
|
rename_variants = "QualifiedScreamingSnakeCase"
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,10 +6,10 @@ int main(void) {
|
||||||
if (connection == NULL)
|
if (connection == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
SPPixelGrid *pixels = sp_pixel_grid_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
|
SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
|
||||||
sp_pixel_grid_fill(pixels, true);
|
sp_bitmap_fill(pixels, true);
|
||||||
|
|
||||||
SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
|
SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, SP_COMPRESSION_CODE_UNCOMPRESSED);
|
||||||
while (sp_connection_send_command(connection, sp_command_clone(command)));
|
while (sp_connection_send_command(connection, sp_command_clone(command)));
|
||||||
|
|
||||||
sp_command_free(command);
|
sp_command_free(command);
|
||||||
|
|
281
crates/servicepoint_binding_c/src/bitmap.rs
Normal file
281
crates/servicepoint_binding_c/src/bitmap.rs
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
//! C functions for interacting with [SPBitmap]s
|
||||||
|
//!
|
||||||
|
//! prefix `sp_bitmap_`
|
||||||
|
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
use servicepoint::{DataRef, Grid};
|
||||||
|
|
||||||
|
use crate::byte_slice::SPByteSlice;
|
||||||
|
|
||||||
|
/// A grid of pixels.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```C
|
||||||
|
/// Cp437Grid grid = sp_bitmap_new(8, 3);
|
||||||
|
/// sp_bitmap_fill(grid, true);
|
||||||
|
/// sp_bitmap_set(grid, 0, 0, false);
|
||||||
|
/// sp_bitmap_free(grid);
|
||||||
|
/// ```
|
||||||
|
pub struct SPBitmap(pub(crate) servicepoint::Bitmap);
|
||||||
|
|
||||||
|
/// Creates a new [SPBitmap] with the specified dimensions.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `width`: size in pixels in x-direction
|
||||||
|
/// - `height`: size in pixels in y-direction
|
||||||
|
///
|
||||||
|
/// returns: [SPBitmap] initialized to all pixels off. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when the width is not dividable by 8
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller has to make sure that:
|
||||||
|
///
|
||||||
|
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||||
|
/// by explicitly calling `sp_bitmap_free`.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn sp_bitmap_new(
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
) -> NonNull<SPBitmap> {
|
||||||
|
let result = Box::new(SPBitmap(servicepoint::Bitmap::new(
|
||||||
|
width, height,
|
||||||
|
)));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads a [SPBitmap] with the specified dimensions from the provided data.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `width`: size in pixels in x-direction
|
||||||
|
/// - `height`: size in pixels in y-direction
|
||||||
|
///
|
||||||
|
/// returns: [SPBitmap] that contains a copy of the provided data. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `data` is NULL
|
||||||
|
/// - when the dimensions and data size do not match exactly.
|
||||||
|
/// - when the width is not dividable by 8
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller has to make sure that:
|
||||||
|
///
|
||||||
|
/// - `data` points to a valid memory location of at least `data_length` bytes in size.
|
||||||
|
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||||
|
/// by explicitly calling `sp_bitmap_free`.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn sp_bitmap_load(
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
data: *const u8,
|
||||||
|
data_length: usize,
|
||||||
|
) -> NonNull<SPBitmap> {
|
||||||
|
assert!(!data.is_null());
|
||||||
|
let data = std::slice::from_raw_parts(data, data_length);
|
||||||
|
let result = Box::new(SPBitmap(servicepoint::Bitmap::load(
|
||||||
|
width, height, data,
|
||||||
|
)));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clones a [SPBitmap].
|
||||||
|
///
|
||||||
|
/// Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bitmap` is NULL
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller has to make sure that:
|
||||||
|
///
|
||||||
|
/// - `bitmap` points to a valid [SPBitmap]
|
||||||
|
/// - `bitmap` is not written to concurrently
|
||||||
|
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||||
|
/// by explicitly calling `sp_bitmap_free`.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn sp_bitmap_clone(
|
||||||
|
bitmap: *const SPBitmap,
|
||||||
|
) -> NonNull<SPBitmap> {
|
||||||
|
assert!(!bitmap.is_null());
|
||||||
|
let result = Box::new(SPBitmap((*bitmap).0.clone()));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deallocates a [SPBitmap].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bitmap` is NULL
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller has to make sure that:
|
||||||
|
///
|
||||||
|
/// - `bitmap` points to a valid [SPBitmap]
|
||||||
|
/// - `bitmap` is not used concurrently or after bitmap call
|
||||||
|
/// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand]
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) {
|
||||||
|
assert!(!bitmap.is_null());
|
||||||
|
_ = Box::from_raw(bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the current value at the specified position in the [SPBitmap].
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `bitmap`: instance to read from
|
||||||
|
/// - `x` and `y`: position of the cell to read
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bitmap` is NULL
|
||||||
|
/// - when accessing `x` or `y` out of bounds
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller has to make sure that:
|
||||||
|
///
|
||||||
|
/// - `bitmap` points to a valid [SPBitmap]
|
||||||
|
/// - `bitmap` is not written to concurrently
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn sp_bitmap_get(
|
||||||
|
bitmap: *const SPBitmap,
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
) -> bool {
|
||||||
|
assert!(!bitmap.is_null());
|
||||||
|
(*bitmap).0.get(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the value of the specified position in the [SPBitmap].
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `bitmap`: instance to write to
|
||||||
|
/// - `x` and `y`: position of the cell
|
||||||
|
/// - `value`: the value to write to the cell
|
||||||
|
///
|
||||||
|
/// returns: old value of the cell
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bitmap` is NULL
|
||||||
|
/// - when accessing `x` or `y` out of bounds
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller has to make sure that:
|
||||||
|
///
|
||||||
|
/// - `bitmap` points to a valid [SPBitmap]
|
||||||
|
/// - `bitmap` is not written to or read from concurrently
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn sp_bitmap_set(
|
||||||
|
bitmap: *mut SPBitmap,
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
value: bool,
|
||||||
|
) {
|
||||||
|
assert!(!bitmap.is_null());
|
||||||
|
(*bitmap).0.set(x, y, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the state of all pixels in the [SPBitmap].
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `bitmap`: instance to write to
|
||||||
|
/// - `value`: the value to set all pixels to
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bitmap` is NULL
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller has to make sure that:
|
||||||
|
///
|
||||||
|
/// - `bitmap` points to a valid [SPBitmap]
|
||||||
|
/// - `bitmap` is not written to or read from concurrently
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn sp_bitmap_fill(bitmap: *mut SPBitmap, value: bool) {
|
||||||
|
assert!(!bitmap.is_null());
|
||||||
|
(*bitmap).0.fill(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the width in pixels of the [SPBitmap] instance.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `bitmap`: instance to read from
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bitmap` is NULL
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller has to make sure that:
|
||||||
|
///
|
||||||
|
/// - `bitmap` points to a valid [SPBitmap]
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn sp_bitmap_width(bitmap: *const SPBitmap) -> usize {
|
||||||
|
assert!(!bitmap.is_null());
|
||||||
|
(*bitmap).0.width()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the height in pixels of the [SPBitmap] instance.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `bitmap`: instance to read from
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bitmap` is NULL
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller has to make sure that:
|
||||||
|
///
|
||||||
|
/// - `bitmap` points to a valid [SPBitmap]
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn sp_bitmap_height(bitmap: *const SPBitmap) -> usize {
|
||||||
|
assert!(!bitmap.is_null());
|
||||||
|
(*bitmap).0.height()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets an unsafe reference to the data of the [SPBitmap] instance.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bitmap` is NULL
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller has to make sure that:
|
||||||
|
///
|
||||||
|
/// - `bitmap` points to a valid [SPBitmap]
|
||||||
|
/// - the returned memory range is never accessed after the passed [SPBitmap] has been freed
|
||||||
|
/// - the returned memory range is never accessed concurrently, either via the [SPBitmap] or directly
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn sp_bitmap_unsafe_data_ref(
|
||||||
|
bitmap: *mut SPBitmap,
|
||||||
|
) -> SPByteSlice {
|
||||||
|
assert!(!bitmap.is_null());
|
||||||
|
let data = (*bitmap).0.data_ref_mut();
|
||||||
|
SPByteSlice {
|
||||||
|
start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
|
||||||
|
length: data.len(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
//! C functions for interacting with `SPBitVec`s
|
//! C functions for interacting with [SPBitVec]s
|
||||||
//!
|
//!
|
||||||
//! prefix `sp_bit_vec_`
|
//! prefix `sp_bitvec_`
|
||||||
|
|
||||||
|
use std::ptr::NonNull;
|
||||||
use crate::SPByteSlice;
|
use crate::SPByteSlice;
|
||||||
use servicepoint::bitvec::prelude::{BitVec, Msb0};
|
use servicepoint::bitvec::prelude::{BitVec, Msb0};
|
||||||
|
|
||||||
|
@ -9,9 +10,9 @@ use servicepoint::bitvec::prelude::{BitVec, Msb0};
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```C
|
/// ```C
|
||||||
/// SPBitVec vec = sp_bit_vec_new(8);
|
/// SPBitVec vec = sp_bitvec_new(8);
|
||||||
/// sp_bit_vec_set(vec, 5, true);
|
/// sp_bitvec_set(vec, 5, true);
|
||||||
/// sp_bit_vec_free(vec);
|
/// sp_bitvec_free(vec);
|
||||||
/// ```
|
/// ```
|
||||||
pub struct SPBitVec(BitVec<u8, Msb0>);
|
pub struct SPBitVec(BitVec<u8, Msb0>);
|
||||||
|
|
||||||
|
@ -33,30 +34,37 @@ impl Clone for SPBitVec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `SPBitVec` instance.
|
/// Creates a new [SPBitVec] instance.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `size`: size in bits.
|
/// - `size`: size in bits.
|
||||||
///
|
///
|
||||||
/// returns: `SPBitVec` with all bits set to false. Will never return NULL.
|
/// returns: [SPBitVec] with all bits set to false. Will never return NULL.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When `size` is not divisible by 8.
|
/// - when `size` is not divisible by 8.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_bit_vec_free`.
|
/// by explicitly calling `sp_bitvec_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_bit_vec_new(size: usize) -> *mut SPBitVec {
|
pub unsafe extern "C" fn sp_bitvec_new(size: usize) -> NonNull<SPBitVec> {
|
||||||
Box::into_raw(Box::new(SPBitVec(BitVec::repeat(false, size))))
|
let result = Box::new(SPBitVec(BitVec::repeat(false, size)));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interpret the data as a series of bits and load then into a new `SPBitVec` instance.
|
/// Interpret the data as a series of bits and load then into a new [SPBitVec] instance.
|
||||||
|
///
|
||||||
|
/// returns: [SPBitVec] instance containing data. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `data` is NULL
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
@ -65,48 +73,63 @@ pub unsafe extern "C" fn sp_bit_vec_new(size: usize) -> *mut SPBitVec {
|
||||||
/// - `data` points to a valid memory location of at least `data_length`
|
/// - `data` points to a valid memory location of at least `data_length`
|
||||||
/// bytes in size.
|
/// bytes in size.
|
||||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_bit_vec_free`.
|
/// by explicitly calling `sp_bitvec_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_bit_vec_load(
|
pub unsafe extern "C" fn sp_bitvec_load(
|
||||||
data: *const u8,
|
data: *const u8,
|
||||||
data_length: usize,
|
data_length: usize,
|
||||||
) -> *mut SPBitVec {
|
) -> NonNull<SPBitVec> {
|
||||||
|
assert!(!data.is_null());
|
||||||
let data = std::slice::from_raw_parts(data, data_length);
|
let data = std::slice::from_raw_parts(data, data_length);
|
||||||
Box::into_raw(Box::new(SPBitVec(BitVec::from_slice(data))))
|
let result = Box::new(SPBitVec(BitVec::from_slice(data)));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clones a `SPBitVec`.
|
/// Clones a [SPBitVec].
|
||||||
|
///
|
||||||
|
/// returns: new [SPBitVec] instance. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bit_vec` is NULL
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid `SPBitVec`
|
/// - `bit_vec` points to a valid [SPBitVec]
|
||||||
/// - `bit_vec` is not written to concurrently
|
/// - `bit_vec` is not written to concurrently
|
||||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_bit_vec_free`.
|
/// by explicitly calling `sp_bitvec_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_bit_vec_clone(
|
pub unsafe extern "C" fn sp_bitvec_clone(
|
||||||
bit_vec: *const SPBitVec,
|
bit_vec: *const SPBitVec,
|
||||||
) -> *mut SPBitVec {
|
) -> NonNull<SPBitVec> {
|
||||||
Box::into_raw(Box::new((*bit_vec).clone()))
|
assert!(!bit_vec.is_null());
|
||||||
|
let result = Box::new((*bit_vec).clone());
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deallocates a `SPBitVec`.
|
/// Deallocates a [SPBitVec].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `but_vec` is NULL
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid `SPBitVec`
|
/// - `bit_vec` points to a valid [SPBitVec]
|
||||||
/// - `bit_vec` is not used concurrently or after this call
|
/// - `bit_vec` is not used concurrently or after this call
|
||||||
/// - `bit_vec` was not passed to another consuming function, e.g. to create a `SPCommand`
|
/// - `bit_vec` was not passed to another consuming function, e.g. to create a [SPCommand]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_bit_vec_free(bit_vec: *mut SPBitVec) {
|
pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) {
|
||||||
|
assert!(!bit_vec.is_null());
|
||||||
_ = Box::from_raw(bit_vec);
|
_ = Box::from_raw(bit_vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the value of a bit from the `SPBitVec`.
|
/// Gets the value of a bit from the [SPBitVec].
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
|
@ -117,23 +140,25 @@ pub unsafe extern "C" fn sp_bit_vec_free(bit_vec: *mut SPBitVec) {
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When accessing `index` out of bounds.
|
/// - when `bit_vec` is NULL
|
||||||
|
/// - when accessing `index` out of bounds
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid `SPBitVec`
|
/// - `bit_vec` points to a valid [SPBitVec]
|
||||||
/// - `bit_vec` is not written to concurrently
|
/// - `bit_vec` is not written to concurrently
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_bit_vec_get(
|
pub unsafe extern "C" fn sp_bitvec_get(
|
||||||
bit_vec: *const SPBitVec,
|
bit_vec: *const SPBitVec,
|
||||||
index: usize,
|
index: usize,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
assert!(!bit_vec.is_null());
|
||||||
*(*bit_vec).0.get(index).unwrap()
|
*(*bit_vec).0.get(index).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the value of a bit in the `SPBitVec`.
|
/// Sets the value of a bit in the [SPBitVec].
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
|
@ -141,58 +166,68 @@ pub unsafe extern "C" fn sp_bit_vec_get(
|
||||||
/// - `index`: the bit index to edit
|
/// - `index`: the bit index to edit
|
||||||
/// - `value`: the value to set the bit to
|
/// - `value`: the value to set the bit to
|
||||||
///
|
///
|
||||||
/// returns: old value of the bit
|
|
||||||
///
|
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When accessing `index` out of bounds.
|
/// - when `bit_vec` is NULL
|
||||||
|
/// - when accessing `index` out of bounds
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid `SPBitVec`
|
/// - `bit_vec` points to a valid [SPBitVec]
|
||||||
/// - `bit_vec` is not written to or read from concurrently
|
/// - `bit_vec` is not written to or read from concurrently
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_bit_vec_set(
|
pub unsafe extern "C" fn sp_bitvec_set(
|
||||||
bit_vec: *mut SPBitVec,
|
bit_vec: *mut SPBitVec,
|
||||||
index: usize,
|
index: usize,
|
||||||
value: bool,
|
value: bool,
|
||||||
) {
|
) {
|
||||||
|
assert!(!bit_vec.is_null());
|
||||||
(*bit_vec).0.set(index, value)
|
(*bit_vec).0.set(index, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the value of all bits in the `SPBitVec`.
|
/// Sets the value of all bits in the [SPBitVec].
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `bit_vec`: instance to write to
|
/// - `bit_vec`: instance to write to
|
||||||
/// - `value`: the value to set all bits to
|
/// - `value`: the value to set all bits to
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bit_vec` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid `SPBitVec`
|
/// - `bit_vec` points to a valid [SPBitVec]
|
||||||
/// - `bit_vec` is not written to or read from concurrently
|
/// - `bit_vec` is not written to or read from concurrently
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_bit_vec_fill(bit_vec: *mut SPBitVec, value: bool) {
|
pub unsafe extern "C" fn sp_bitvec_fill(bit_vec: *mut SPBitVec, value: bool) {
|
||||||
|
assert!(!bit_vec.is_null());
|
||||||
(*bit_vec).0.fill(value)
|
(*bit_vec).0.fill(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the length of the `SPBitVec` in bits.
|
/// Gets the length of the [SPBitVec] in bits.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `bit_vec`: instance to write to
|
/// - `bit_vec`: instance to write to
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bit_vec` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid `SPBitVec`
|
/// - `bit_vec` points to a valid [SPBitVec]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_bit_vec_len(bit_vec: *const SPBitVec) -> usize {
|
pub unsafe extern "C" fn sp_bitvec_len(bit_vec: *const SPBitVec) -> usize {
|
||||||
|
assert!(!bit_vec.is_null());
|
||||||
(*bit_vec).0.len()
|
(*bit_vec).0.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,36 +237,46 @@ pub unsafe extern "C" fn sp_bit_vec_len(bit_vec: *const SPBitVec) -> usize {
|
||||||
///
|
///
|
||||||
/// - `bit_vec`: instance to write to
|
/// - `bit_vec`: instance to write to
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bit_vec` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid `SPBitVec`
|
/// - `bit_vec` points to a valid [SPBitVec]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_bit_vec_is_empty(bit_vec: *const SPBitVec) -> bool {
|
pub unsafe extern "C" fn sp_bitvec_is_empty(bit_vec: *const SPBitVec) -> bool {
|
||||||
|
assert!(!bit_vec.is_null());
|
||||||
(*bit_vec).0.is_empty()
|
(*bit_vec).0.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an unsafe reference to the data of the `SPBitVec` instance.
|
/// Gets an unsafe reference to the data of the [SPBitVec] instance.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `bit_vec`: instance to write to
|
/// - `bit_vec`: instance to write to
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bit_vec` is NULL
|
||||||
|
///
|
||||||
/// ## Safety
|
/// ## Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid `SPBitVec`
|
/// - `bit_vec` points to a valid [SPBitVec]
|
||||||
/// - the returned memory range is never accessed after the passed `SPBitVec` has been freed
|
/// - the returned memory range is never accessed after the passed [SPBitVec] has been freed
|
||||||
/// - the returned memory range is never accessed concurrently, either via the `SPBitVec` or directly
|
/// - the returned memory range is never accessed concurrently, either via the [SPBitVec] or directly
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_bit_vec_unsafe_data_ref(
|
pub unsafe extern "C" fn sp_bitvec_unsafe_data_ref(
|
||||||
bit_vec: *mut SPBitVec,
|
bit_vec: *mut SPBitVec,
|
||||||
) -> SPByteSlice {
|
) -> SPByteSlice {
|
||||||
|
assert!(!bit_vec.is_null());
|
||||||
let data = (*bit_vec).0.as_raw_mut_slice();
|
let data = (*bit_vec).0.as_raw_mut_slice();
|
||||||
SPByteSlice {
|
SPByteSlice {
|
||||||
start: data.as_mut_ptr_range().start,
|
start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
|
||||||
length: data.len(),
|
length: data.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,19 @@
|
||||||
//! C functions for interacting with `SPBrightnessGrid`s
|
//! C functions for interacting with [SPBrightnessGrid]s
|
||||||
//!
|
//!
|
||||||
//! prefix `sp_brightness_grid_`
|
//! prefix `sp_brightness_grid_`
|
||||||
|
|
||||||
use crate::SPByteSlice;
|
use crate::SPByteSlice;
|
||||||
use servicepoint::{Brightness, DataRef, Grid, PrimitiveGrid};
|
use servicepoint::{Brightness, DataRef, Grid, PrimitiveGrid};
|
||||||
|
use std::convert::Into;
|
||||||
use std::intrinsics::transmute;
|
use std::intrinsics::transmute;
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
/// see [Brightness::MIN]
|
||||||
|
pub const SP_BRIGHTNESS_MIN: u8 = 0;
|
||||||
|
/// see [Brightness::MAX]
|
||||||
|
pub const SP_BRIGHTNESS_MAX: u8 = 11;
|
||||||
|
/// Count of possible brightness values
|
||||||
|
pub const SP_BRIGHTNESS_LEVELS: u8 = 12;
|
||||||
|
|
||||||
/// A grid containing brightness values.
|
/// A grid containing brightness values.
|
||||||
///
|
///
|
||||||
|
@ -21,17 +30,12 @@ use std::intrinsics::transmute;
|
||||||
/// SPCommand command = sp_command_char_brightness(grid);
|
/// SPCommand command = sp_command_char_brightness(grid);
|
||||||
/// sp_connection_free(connection);
|
/// sp_connection_free(connection);
|
||||||
/// ```
|
/// ```
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct SPBrightnessGrid(pub(crate) servicepoint::BrightnessGrid);
|
pub struct SPBrightnessGrid(pub(crate) servicepoint::BrightnessGrid);
|
||||||
|
|
||||||
impl Clone for SPBrightnessGrid {
|
/// Creates a new [SPBrightnessGrid] with the specified dimensions.
|
||||||
fn clone(&self) -> Self {
|
|
||||||
SPBrightnessGrid(self.0.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new `SPBrightnessGrid` with the specified dimensions.
|
|
||||||
///
|
///
|
||||||
/// returns: `SPBrightnessGrid` initialized to 0. Will never return NULL.
|
/// returns: [SPBrightnessGrid] initialized to 0. Will never return NULL.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
@ -43,17 +47,21 @@ impl Clone for SPBrightnessGrid {
|
||||||
pub unsafe extern "C" fn sp_brightness_grid_new(
|
pub unsafe extern "C" fn sp_brightness_grid_new(
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
) -> *mut SPBrightnessGrid {
|
) -> NonNull<SPBrightnessGrid> {
|
||||||
Box::into_raw(Box::new(SPBrightnessGrid(
|
let result = Box::new(SPBrightnessGrid(
|
||||||
servicepoint::BrightnessGrid::new(width, height),
|
servicepoint::BrightnessGrid::new(width, height),
|
||||||
)))
|
));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a `SPBrightnessGrid` with the specified dimensions from the provided data.
|
/// Loads a [SPBrightnessGrid] with the specified dimensions from the provided data.
|
||||||
|
///
|
||||||
|
/// returns: new [SPBrightnessGrid] instance. Will never return NULL.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When the provided `data_length` is not sufficient for the `height` and `width`
|
/// - when `data` is NULL
|
||||||
|
/// - when the provided `data_length` does not match `height` and `width`
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
@ -69,52 +77,67 @@ pub unsafe extern "C" fn sp_brightness_grid_load(
|
||||||
height: usize,
|
height: usize,
|
||||||
data: *const u8,
|
data: *const u8,
|
||||||
data_length: usize,
|
data_length: usize,
|
||||||
) -> *mut SPBrightnessGrid {
|
) -> NonNull<SPBrightnessGrid> {
|
||||||
|
assert!(!data.is_null());
|
||||||
let data = std::slice::from_raw_parts(data, data_length);
|
let data = std::slice::from_raw_parts(data, data_length);
|
||||||
let grid = PrimitiveGrid::load(width, height, data);
|
let grid = PrimitiveGrid::load(width, height, data);
|
||||||
let grid = servicepoint::BrightnessGrid::try_from(grid)
|
let grid = servicepoint::BrightnessGrid::try_from(grid)
|
||||||
.expect("invalid brightness value");
|
.expect("invalid brightness value");
|
||||||
Box::into_raw(Box::new(SPBrightnessGrid(grid)))
|
let result = Box::new(SPBrightnessGrid(grid));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clones a `SPBrightnessGrid`.
|
/// Clones a [SPBrightnessGrid].
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `brightness_grid`: instance to read from
|
/// - `brightness_grid`: instance to read from
|
||||||
///
|
///
|
||||||
|
/// returns: new [SPBrightnessGrid] instance. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `brightness_grid` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
|
||||||
/// - `brightness_grid` is not written to concurrently
|
/// - `brightness_grid` is not written to concurrently
|
||||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_brightness_grid_free`.
|
/// by explicitly calling `sp_brightness_grid_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_brightness_grid_clone(
|
pub unsafe extern "C" fn sp_brightness_grid_clone(
|
||||||
brightness_grid: *const SPBrightnessGrid,
|
brightness_grid: *const SPBrightnessGrid,
|
||||||
) -> *mut SPBrightnessGrid {
|
) -> NonNull<SPBrightnessGrid> {
|
||||||
Box::into_raw(Box::new((*brightness_grid).clone()))
|
assert!(!brightness_grid.is_null());
|
||||||
|
let result = Box::new((*brightness_grid).clone());
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deallocates a `SPBrightnessGrid`.
|
/// Deallocates a [SPBrightnessGrid].
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `brightness_grid`: instance to read from
|
/// - `brightness_grid`: instance to read from
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `brightness_grid` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
|
||||||
/// - `brightness_grid` is not used concurrently or after this call
|
/// - `brightness_grid` is not used concurrently or after this call
|
||||||
/// - `brightness_grid` was not passed to another consuming function, e.g. to create a `SPCommand`
|
/// - `brightness_grid` was not passed to another consuming function, e.g. to create a [SPCommand]
|
||||||
#[no_mangle]
|
#[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,
|
||||||
) {
|
) {
|
||||||
|
assert!(!brightness_grid.is_null());
|
||||||
_ = Box::from_raw(brightness_grid);
|
_ = Box::from_raw(brightness_grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,15 +148,18 @@ pub unsafe extern "C" fn sp_brightness_grid_free(
|
||||||
/// - `brightness_grid`: instance to read from
|
/// - `brightness_grid`: instance to read from
|
||||||
/// - `x` and `y`: position of the cell to read
|
/// - `x` and `y`: position of the cell to read
|
||||||
///
|
///
|
||||||
|
/// returns: value at position
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When accessing `x` or `y` out of bounds.
|
/// - when `brightness_grid` is NULL
|
||||||
|
/// - When accessing `x` or `y` out of bounds.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
|
||||||
/// - `brightness_grid` is not written to concurrently
|
/// - `brightness_grid` is not written to concurrently
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_brightness_grid_get(
|
pub unsafe extern "C" fn sp_brightness_grid_get(
|
||||||
|
@ -141,10 +167,11 @@ pub unsafe extern "C" fn sp_brightness_grid_get(
|
||||||
x: usize,
|
x: usize,
|
||||||
y: usize,
|
y: usize,
|
||||||
) -> u8 {
|
) -> u8 {
|
||||||
|
assert!(!brightness_grid.is_null());
|
||||||
(*brightness_grid).0.get(x, y).into()
|
(*brightness_grid).0.get(x, y).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the value of the specified position in the `SPBrightnessGrid`.
|
/// Sets the value of the specified position in the [SPBrightnessGrid].
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
|
@ -156,6 +183,7 @@ pub unsafe extern "C" fn sp_brightness_grid_get(
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
/// - when `brightness_grid` is NULL
|
||||||
/// - When accessing `x` or `y` out of bounds.
|
/// - When accessing `x` or `y` out of bounds.
|
||||||
/// - When providing an invalid brightness value
|
/// - When providing an invalid brightness value
|
||||||
///
|
///
|
||||||
|
@ -163,7 +191,7 @@ pub unsafe extern "C" fn sp_brightness_grid_get(
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `brightness_grid` points to a valid `SPBitVec`
|
/// - `brightness_grid` points to a valid [SPBitVec]
|
||||||
/// - `brightness_grid` is not written to or read from concurrently
|
/// - `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(
|
||||||
|
@ -172,12 +200,13 @@ pub unsafe extern "C" fn sp_brightness_grid_set(
|
||||||
y: usize,
|
y: usize,
|
||||||
value: u8,
|
value: u8,
|
||||||
) {
|
) {
|
||||||
|
assert!(!brightness_grid.is_null());
|
||||||
let brightness =
|
let brightness =
|
||||||
Brightness::try_from(value).expect("invalid brightness value");
|
Brightness::try_from(value).expect("invalid brightness value");
|
||||||
(*brightness_grid).0.set(x, y, brightness);
|
(*brightness_grid).0.set(x, y, brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the value of all cells in the `SPBrightnessGrid`.
|
/// Sets the value of all cells in the [SPBrightnessGrid].
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
|
@ -186,83 +215,106 @@ pub unsafe extern "C" fn sp_brightness_grid_set(
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
/// - when `brightness_grid` is NULL
|
||||||
/// - When providing an invalid brightness value
|
/// - When providing an invalid brightness value
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
|
||||||
/// - `brightness_grid` is not written to or read from concurrently
|
/// - `brightness_grid` is not written to or read from concurrently
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_brightness_grid_fill(
|
pub unsafe extern "C" fn sp_brightness_grid_fill(
|
||||||
brightness_grid: *mut SPBrightnessGrid,
|
brightness_grid: *mut SPBrightnessGrid,
|
||||||
value: u8,
|
value: u8,
|
||||||
) {
|
) {
|
||||||
|
assert!(!brightness_grid.is_null());
|
||||||
let brightness =
|
let brightness =
|
||||||
Brightness::try_from(value).expect("invalid brightness value");
|
Brightness::try_from(value).expect("invalid brightness value");
|
||||||
(*brightness_grid).0.fill(brightness);
|
(*brightness_grid).0.fill(brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the width of the `SPBrightnessGrid` instance.
|
/// Gets the width of the [SPBrightnessGrid] instance.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `brightness_grid`: instance to read from
|
/// - `brightness_grid`: instance to read from
|
||||||
///
|
///
|
||||||
|
/// returns: width
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `brightness_grid` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_brightness_grid_width(
|
pub unsafe extern "C" fn sp_brightness_grid_width(
|
||||||
brightness_grid: *const SPBrightnessGrid,
|
brightness_grid: *const SPBrightnessGrid,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
|
assert!(!brightness_grid.is_null());
|
||||||
(*brightness_grid).0.width()
|
(*brightness_grid).0.width()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the height of the `SPBrightnessGrid` instance.
|
/// Gets the height of the [SPBrightnessGrid] instance.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `brightness_grid`: instance to read from
|
/// - `brightness_grid`: instance to read from
|
||||||
///
|
///
|
||||||
|
/// returns: height
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `brightness_grid` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_brightness_grid_height(
|
pub unsafe extern "C" fn sp_brightness_grid_height(
|
||||||
brightness_grid: *const SPBrightnessGrid,
|
brightness_grid: *const SPBrightnessGrid,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
|
assert!(!brightness_grid.is_null());
|
||||||
(*brightness_grid).0.height()
|
(*brightness_grid).0.height()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an unsafe reference to the data of the `SPBrightnessGrid` instance.
|
/// Gets an unsafe reference to the data of the [SPBrightnessGrid] instance.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `brightness_grid`: instance to read from
|
/// - `brightness_grid`: instance to read from
|
||||||
///
|
///
|
||||||
/// ## Safety
|
/// returns: slice of bytes underlying the `brightness_grid`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `brightness_grid` is NULL
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
|
||||||
/// - the returned memory range is never accessed after the passed `SPBrightnessGrid` has been freed
|
/// - the returned memory range is never accessed after the passed [SPBrightnessGrid] has been freed
|
||||||
/// - the returned memory range is never accessed concurrently, either via the `SPBrightnessGrid` or directly
|
/// - the returned memory range is never accessed concurrently, either via the [SPBrightnessGrid] or directly
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref(
|
pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref(
|
||||||
brightness_grid: *mut SPBrightnessGrid,
|
brightness_grid: *mut SPBrightnessGrid,
|
||||||
) -> SPByteSlice {
|
) -> SPByteSlice {
|
||||||
|
assert!(!brightness_grid.is_null());
|
||||||
assert_eq!(core::mem::size_of::<Brightness>(), 1);
|
assert_eq!(core::mem::size_of::<Brightness>(), 1);
|
||||||
|
|
||||||
let data = (*brightness_grid).0.data_ref_mut();
|
let data = (*brightness_grid).0.data_ref_mut();
|
||||||
|
// this assumes more about the memory layout than rust guarantees. yikes!
|
||||||
let data: &mut [u8] = transmute(data);
|
let data: &mut [u8] = transmute(data);
|
||||||
SPByteSlice {
|
SPByteSlice {
|
||||||
start: data.as_mut_ptr_range().start,
|
start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
|
||||||
length: data.len(),
|
length: data.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
//! FFI slice helper
|
//! FFI slice helper
|
||||||
|
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
/// Represents a span of memory (`&mut [u8]` ) as a struct usable by C code.
|
/// Represents a span of memory (`&mut [u8]` ) as a struct usable by C code.
|
||||||
///
|
///
|
||||||
|
@ -16,7 +18,7 @@
|
||||||
/// will try to free the memory of a potentially separate allocator.
|
/// will try to free the memory of a potentially separate allocator.
|
||||||
pub struct SPByteSlice {
|
pub struct SPByteSlice {
|
||||||
/// The start address of the memory
|
/// The start address of the memory
|
||||||
pub start: *mut u8,
|
pub start: NonNull<u8>,
|
||||||
/// The amount of memory in bytes
|
/// The amount of memory in bytes
|
||||||
pub length: usize,
|
pub length: usize,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
//! C functions for interacting with `SPCommand`s
|
//! C functions for interacting with [SPCommand]s
|
||||||
//!
|
//!
|
||||||
//! prefix `sp_command_`
|
//! prefix `sp_command_`
|
||||||
|
|
||||||
use std::ptr::null_mut;
|
use std::ptr::{null_mut, NonNull};
|
||||||
|
|
||||||
use servicepoint::{Brightness, Origin};
|
use servicepoint::{Brightness, Origin};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
SPBitVec, SPBrightnessGrid, SPCompressionCode, SPCp437Grid, SPPacket,
|
SPBitVec, SPBitmap, SPBrightnessGrid, SPCompressionCode, SPCp437Grid,
|
||||||
SPPixelGrid,
|
SPPacket,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A low-level display command.
|
/// A low-level display command.
|
||||||
///
|
///
|
||||||
/// This struct and associated functions implement the UDP protocol for the display.
|
/// This struct and associated functions implement the UDP protocol for the display.
|
||||||
///
|
///
|
||||||
/// To send a `SPCommand`, use a `SPConnection`.
|
/// To send a [SPCommand], use a [SPConnection].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -31,20 +31,24 @@ impl Clone for SPCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to turn a `SPPacket` into a `SPCommand`.
|
/// Tries to turn a [SPPacket] into a [SPCommand].
|
||||||
///
|
///
|
||||||
/// The packet is deallocated in the process.
|
/// The packet is deallocated in the process.
|
||||||
///
|
///
|
||||||
/// Returns: pointer to new `SPCommand` instance or NULL
|
/// Returns: pointer to new [SPCommand] instance or NULL if parsing failed.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `packet` is NULL
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `SPPacket` points to a valid instance of `SPPacket`
|
/// - [SPPacket] points to a valid instance of [SPPacket]
|
||||||
/// - `SPPacket` is not used concurrently or after this call
|
/// - [SPPacket] is not used concurrently or after this call
|
||||||
/// - the result is checked for NULL
|
/// - the result is checked for NULL
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_try_from_packet(
|
pub unsafe extern "C" fn sp_command_try_from_packet(
|
||||||
|
@ -57,28 +61,36 @@ pub unsafe extern "C" fn sp_command_try_from_packet(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clones a `SPCommand` instance.
|
/// Clones a [SPCommand] instance.
|
||||||
|
///
|
||||||
|
/// returns: new [SPCommand] instance. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `command` is NULL
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `command` points to a valid instance of `SPCommand`
|
/// - `command` points to a valid instance of [SPCommand]
|
||||||
/// - `command` is not written to concurrently
|
/// - `command` is not written to concurrently
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_clone(
|
pub unsafe extern "C" fn sp_command_clone(
|
||||||
command: *const SPCommand,
|
command: *const SPCommand,
|
||||||
) -> *mut SPCommand {
|
) -> NonNull<SPCommand> {
|
||||||
Box::into_raw(Box::new((*command).clone()))
|
assert!(!command.is_null());
|
||||||
|
let result = Box::new((*command).clone());
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set all pixels to the off state.
|
/// Set all pixels to the off state.
|
||||||
///
|
///
|
||||||
/// Does not affect brightness.
|
/// Does not affect brightness.
|
||||||
///
|
///
|
||||||
/// Returns: a new `Command::Clear` instance. Will never return NULL.
|
/// Returns: a new [Command::Clear] instance. Will never return NULL.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -90,28 +102,30 @@ pub unsafe extern "C" fn sp_command_clone(
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_clear() -> *mut SPCommand {
|
pub unsafe extern "C" fn sp_command_clear() -> NonNull<SPCommand> {
|
||||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::Clear)))
|
let result = Box::new(SPCommand(servicepoint::Command::Clear));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Kills the udp daemon on the display, which usually results in a restart.
|
/// Kills the udp daemon on the display, which usually results in a restart.
|
||||||
///
|
///
|
||||||
/// 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 [Command::HardReset] instance. Will never return NULL.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_hard_reset() -> *mut SPCommand {
|
pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull<SPCommand> {
|
||||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::HardReset)))
|
let result = Box::new(SPCommand(servicepoint::Command::HardReset));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A yet-to-be-tested command.
|
/// A yet-to-be-tested command.
|
||||||
|
@ -122,16 +136,17 @@ pub unsafe extern "C" fn sp_command_hard_reset() -> *mut SPCommand {
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_fade_out() -> *mut SPCommand {
|
pub unsafe extern "C" fn sp_command_fade_out() -> NonNull<SPCommand> {
|
||||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::FadeOut)))
|
let result = Box::new(SPCommand(servicepoint::Command::FadeOut));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 [Command::Brightness] instance. Will never return NULL.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
@ -141,44 +156,50 @@ pub unsafe extern "C" fn sp_command_fade_out() -> *mut SPCommand {
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_brightness(
|
pub unsafe extern "C" fn sp_command_brightness(
|
||||||
brightness: u8,
|
brightness: u8,
|
||||||
) -> *mut SPCommand {
|
) -> NonNull<SPCommand> {
|
||||||
let brightness =
|
let brightness =
|
||||||
Brightness::try_from(brightness).expect("invalid brightness");
|
Brightness::try_from(brightness).expect("invalid brightness");
|
||||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::Brightness(
|
let result = Box::new(SPCommand(
|
||||||
brightness,
|
servicepoint::Command::Brightness(brightness),
|
||||||
))))
|
));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the brightness of individual tiles in a rectangular area of the display.
|
/// Set the brightness of individual tiles in a rectangular area of the display.
|
||||||
///
|
///
|
||||||
/// The passed `SPBrightnessGrid` gets consumed.
|
/// The passed [SPBrightnessGrid] gets consumed.
|
||||||
///
|
///
|
||||||
/// Returns: a new `Command::CharBrightness` instance. Will never return NULL.
|
/// Returns: a new [Command::CharBrightness] instance. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `grid` is NULL
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `grid` points to a valid instance of `SPBrightnessGrid`
|
/// - `grid` points to a valid instance of [SPBrightnessGrid]
|
||||||
/// - `grid` is not used concurrently or after this call
|
/// - `grid` is not used concurrently or after this call
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_char_brightness(
|
pub unsafe extern "C" fn sp_command_char_brightness(
|
||||||
x: usize,
|
x: usize,
|
||||||
y: usize,
|
y: usize,
|
||||||
grid: *mut SPBrightnessGrid,
|
grid: *mut SPBrightnessGrid,
|
||||||
) -> *mut SPCommand {
|
) -> NonNull<SPCommand> {
|
||||||
|
assert!(!grid.is_null());
|
||||||
let byte_grid = *Box::from_raw(grid);
|
let byte_grid = *Box::from_raw(grid);
|
||||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::CharBrightness(
|
let result = Box::new(SPCommand(
|
||||||
Origin::new(x, y),
|
servicepoint::Command::CharBrightness(Origin::new(x, y), byte_grid.0),
|
||||||
byte_grid.0,
|
));
|
||||||
))))
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set pixel data starting at the pixel offset on screen.
|
/// Set pixel data starting at the pixel offset on screen.
|
||||||
|
@ -186,33 +207,42 @@ pub unsafe extern "C" fn sp_command_char_brightness(
|
||||||
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
||||||
/// once the starting row is full, overwriting will continue on column 0.
|
/// once the starting row is full, overwriting will continue on column 0.
|
||||||
///
|
///
|
||||||
/// The contained `SPBitVec` is always uncompressed.
|
/// The contained [SPBitVec] is always uncompressed.
|
||||||
///
|
///
|
||||||
/// The passed `SPBitVec` gets consumed.
|
/// The passed [SPBitVec] gets consumed.
|
||||||
///
|
///
|
||||||
/// Returns: a new `Command::BitmapLinear` instance. Will never return NULL.
|
/// Returns: a new [Command::BitmapLinear] instance. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bit_vec` is null
|
||||||
|
/// - when `compression_code` is not a valid value
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid instance of `SPBitVec`
|
/// - `bit_vec` points to a valid instance of [SPBitVec]
|
||||||
/// - `bit_vec` is not used concurrently or after this call
|
/// - `bit_vec` is not used concurrently or after this call
|
||||||
/// - `compression` matches one of the allowed enum values
|
/// - `compression` matches one of the allowed enum values
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_bitmap_linear(
|
pub unsafe extern "C" fn sp_command_bitmap_linear(
|
||||||
offset: usize,
|
offset: usize,
|
||||||
bit_vec: *mut SPBitVec,
|
bit_vec: *mut SPBitVec,
|
||||||
compression: SPCompressionCode,
|
compression: SPCompressionCode,
|
||||||
) -> *mut SPCommand {
|
) -> NonNull<SPCommand> {
|
||||||
|
assert!(!bit_vec.is_null());
|
||||||
let bit_vec = *Box::from_raw(bit_vec);
|
let bit_vec = *Box::from_raw(bit_vec);
|
||||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinear(
|
let result = Box::new(SPCommand(
|
||||||
offset,
|
servicepoint::Command::BitmapLinear(
|
||||||
bit_vec.into(),
|
offset,
|
||||||
compression.try_into().expect("invalid compression code"),
|
bit_vec.into(),
|
||||||
))))
|
compression.try_into().expect("invalid compression code"),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set pixel data according to an and-mask starting at the offset.
|
/// Set pixel data according to an and-mask starting at the offset.
|
||||||
|
@ -220,33 +250,42 @@ pub unsafe extern "C" fn sp_command_bitmap_linear(
|
||||||
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
||||||
/// once the starting row is full, overwriting will continue on column 0.
|
/// once the starting row is full, overwriting will continue on column 0.
|
||||||
///
|
///
|
||||||
/// The contained `SPBitVec` is always uncompressed.
|
/// The contained [SPBitVec] is always uncompressed.
|
||||||
///
|
///
|
||||||
/// The passed `SPBitVec` gets consumed.
|
/// The passed [SPBitVec] gets consumed.
|
||||||
///
|
///
|
||||||
/// Returns: a new `Command::BitmapLinearAnd` instance. Will never return NULL.
|
/// Returns: a new [Command::BitmapLinearAnd] instance. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bit_vec` is null
|
||||||
|
/// - when `compression_code` is not a valid value
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid instance of `SPBitVec`
|
/// - `bit_vec` points to a valid instance of [SPBitVec]
|
||||||
/// - `bit_vec` is not used concurrently or after this call
|
/// - `bit_vec` is not used concurrently or after this call
|
||||||
/// - `compression` matches one of the allowed enum values
|
/// - `compression` matches one of the allowed enum values
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_bitmap_linear_and(
|
pub unsafe extern "C" fn sp_command_bitmap_linear_and(
|
||||||
offset: usize,
|
offset: usize,
|
||||||
bit_vec: *mut SPBitVec,
|
bit_vec: *mut SPBitVec,
|
||||||
compression: SPCompressionCode,
|
compression: SPCompressionCode,
|
||||||
) -> *mut SPCommand {
|
) -> NonNull<SPCommand> {
|
||||||
|
assert!(!bit_vec.is_null());
|
||||||
let bit_vec = *Box::from_raw(bit_vec);
|
let bit_vec = *Box::from_raw(bit_vec);
|
||||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearAnd(
|
let result = Box::new(SPCommand(
|
||||||
offset,
|
servicepoint::Command::BitmapLinearAnd(
|
||||||
bit_vec.into(),
|
offset,
|
||||||
compression.try_into().expect("invalid compression code"),
|
bit_vec.into(),
|
||||||
))))
|
compression.try_into().expect("invalid compression code"),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set pixel data according to an or-mask starting at the offset.
|
/// Set pixel data according to an or-mask starting at the offset.
|
||||||
|
@ -254,33 +293,42 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_and(
|
||||||
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
||||||
/// once the starting row is full, overwriting will continue on column 0.
|
/// once the starting row is full, overwriting will continue on column 0.
|
||||||
///
|
///
|
||||||
/// The contained `SPBitVec` is always uncompressed.
|
/// The contained [SPBitVec] is always uncompressed.
|
||||||
///
|
///
|
||||||
/// The passed `SPBitVec` gets consumed.
|
/// The passed [SPBitVec] gets consumed.
|
||||||
///
|
///
|
||||||
/// Returns: a new `Command::BitmapLinearOr` instance. Will never return NULL.
|
/// Returns: a new [Command::BitmapLinearOr] instance. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bit_vec` is null
|
||||||
|
/// - when `compression_code` is not a valid value
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid instance of `SPBitVec`
|
/// - `bit_vec` points to a valid instance of [SPBitVec]
|
||||||
/// - `bit_vec` is not used concurrently or after this call
|
/// - `bit_vec` is not used concurrently or after this call
|
||||||
/// - `compression` matches one of the allowed enum values
|
/// - `compression` matches one of the allowed enum values
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_bitmap_linear_or(
|
pub unsafe extern "C" fn sp_command_bitmap_linear_or(
|
||||||
offset: usize,
|
offset: usize,
|
||||||
bit_vec: *mut SPBitVec,
|
bit_vec: *mut SPBitVec,
|
||||||
compression: SPCompressionCode,
|
compression: SPCompressionCode,
|
||||||
) -> *mut SPCommand {
|
) -> NonNull<SPCommand> {
|
||||||
|
assert!(!bit_vec.is_null());
|
||||||
let bit_vec = *Box::from_raw(bit_vec);
|
let bit_vec = *Box::from_raw(bit_vec);
|
||||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearOr(
|
let result = Box::new(SPCommand(
|
||||||
offset,
|
servicepoint::Command::BitmapLinearOr(
|
||||||
bit_vec.into(),
|
offset,
|
||||||
compression.try_into().expect("invalid compression code"),
|
bit_vec.into(),
|
||||||
))))
|
compression.try_into().expect("invalid compression code"),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set pixel data according to a xor-mask starting at the offset.
|
/// Set pixel data according to a xor-mask starting at the offset.
|
||||||
|
@ -288,100 +336,118 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_or(
|
||||||
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
||||||
/// once the starting row is full, overwriting will continue on column 0.
|
/// once the starting row is full, overwriting will continue on column 0.
|
||||||
///
|
///
|
||||||
/// The contained `SPBitVec` is always uncompressed.
|
/// The contained [SPBitVec] is always uncompressed.
|
||||||
///
|
///
|
||||||
/// The passed `SPBitVec` gets consumed.
|
/// The passed [SPBitVec] gets consumed.
|
||||||
///
|
///
|
||||||
/// Returns: a new `Command::BitmapLinearXor` instance. Will never return NULL.
|
/// Returns: a new [Command::BitmapLinearXor] instance. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bit_vec` is null
|
||||||
|
/// - when `compression_code` is not a valid value
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `bit_vec` points to a valid instance of `SPBitVec`
|
/// - `bit_vec` points to a valid instance of [SPBitVec]
|
||||||
/// - `bit_vec` is not used concurrently or after this call
|
/// - `bit_vec` is not used concurrently or after this call
|
||||||
/// - `compression` matches one of the allowed enum values
|
/// - `compression` matches one of the allowed enum values
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
|
pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
|
||||||
offset: usize,
|
offset: usize,
|
||||||
bit_vec: *mut SPBitVec,
|
bit_vec: *mut SPBitVec,
|
||||||
compression: SPCompressionCode,
|
compression: SPCompressionCode,
|
||||||
) -> *mut SPCommand {
|
) -> NonNull<SPCommand> {
|
||||||
|
assert!(!bit_vec.is_null());
|
||||||
let bit_vec = *Box::from_raw(bit_vec);
|
let bit_vec = *Box::from_raw(bit_vec);
|
||||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearXor(
|
let result = Box::new(SPCommand(
|
||||||
offset,
|
servicepoint::Command::BitmapLinearXor(
|
||||||
bit_vec.into(),
|
offset,
|
||||||
compression.try_into().expect("invalid compression code"),
|
bit_vec.into(),
|
||||||
))))
|
compression.try_into().expect("invalid compression code"),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show text on the screen.
|
/// Show text on the screen.
|
||||||
///
|
///
|
||||||
/// <div class="warning">
|
/// The passed [SPCp437Grid] gets consumed.
|
||||||
/// The library does not currently convert between UTF-8 and CP-437.
|
|
||||||
/// Because Rust expects UTF-8 strings, it might be necessary to only send ASCII for now.
|
|
||||||
/// </div>
|
|
||||||
///
|
///
|
||||||
/// The passed `SPCp437Grid` gets consumed.///
|
/// Returns: a new [Command::Cp437Data] instance. Will never return NULL.
|
||||||
///
|
///
|
||||||
/// Returns: a new `Command::Cp437Data` instance. Will never return NULL.
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `grid` is null
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `grid` points to a valid instance of `SPCp437Grid`
|
/// - `grid` points to a valid instance of [SPCp437Grid]
|
||||||
/// - `grid` is not used concurrently or after this call
|
/// - `grid` is not used concurrently or after this call
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_cp437_data(
|
pub unsafe extern "C" fn sp_command_cp437_data(
|
||||||
x: usize,
|
x: usize,
|
||||||
y: usize,
|
y: usize,
|
||||||
grid: *mut SPCp437Grid,
|
grid: *mut SPCp437Grid,
|
||||||
) -> *mut SPCommand {
|
) -> NonNull<SPCommand> {
|
||||||
|
assert!(!grid.is_null());
|
||||||
let grid = *Box::from_raw(grid);
|
let grid = *Box::from_raw(grid);
|
||||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::Cp437Data(
|
let result = Box::new(SPCommand(
|
||||||
Origin::new(x, y),
|
servicepoint::Command::Cp437Data(Origin::new(x, y), grid.0),
|
||||||
grid.0,
|
));
|
||||||
))))
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a window of pixels to the specified values.
|
/// Sets a window of pixels to the specified values.
|
||||||
///
|
///
|
||||||
/// The passed `SPPixelGrid` gets consumed.
|
/// The passed [SPBitmap] gets consumed.
|
||||||
///
|
///
|
||||||
/// Returns: a new `Command::BitmapLinearWin` instance. Will never return NULL.
|
/// Returns: a new [Command::BitmapLinearWin] instance. Will never return NULL.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `bitmap` is null
|
||||||
|
/// - when `compression_code` is not a valid value
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `pixel_grid` points to a valid instance of `SPPixelGrid`
|
/// - `bitmap` points to a valid instance of [SPBitmap]
|
||||||
/// - `pixel_grid` is not used concurrently or after this call
|
/// - `bitmap` is not used concurrently or after this call
|
||||||
/// - `compression` matches one of the allowed enum values
|
/// - `compression` matches one of the allowed enum values
|
||||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_command_free`.
|
/// by explicitly calling `sp_command_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_bitmap_linear_win(
|
pub unsafe extern "C" fn sp_command_bitmap_linear_win(
|
||||||
x: usize,
|
x: usize,
|
||||||
y: usize,
|
y: usize,
|
||||||
pixel_grid: *mut SPPixelGrid,
|
bitmap: *mut SPBitmap,
|
||||||
compression_code: SPCompressionCode,
|
compression_code: SPCompressionCode,
|
||||||
) -> *mut SPCommand {
|
) -> NonNull<SPCommand> {
|
||||||
let byte_grid = (*Box::from_raw(pixel_grid)).0;
|
assert!(!bitmap.is_null());
|
||||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearWin(
|
let byte_grid = (*Box::from_raw(bitmap)).0;
|
||||||
Origin::new(x, y),
|
let result = Box::new(SPCommand(
|
||||||
byte_grid,
|
servicepoint::Command::BitmapLinearWin(
|
||||||
compression_code
|
Origin::new(x, y),
|
||||||
.try_into()
|
byte_grid,
|
||||||
.expect("invalid compression code"),
|
compression_code
|
||||||
))))
|
.try_into()
|
||||||
|
.expect("invalid compression code"),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deallocates a `SPCommand`.
|
/// Deallocates a [SPCommand].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -390,14 +456,19 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_win(
|
||||||
/// sp_command_free(c);
|
/// sp_command_free(c);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `command` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `command` points to a valid `SPCommand`
|
/// - `command` points to a valid [SPCommand]
|
||||||
/// - `command` is not used concurrently or after this call
|
/// - `command` is not used concurrently or after this call
|
||||||
/// - `command` was not passed to another consuming function, e.g. to create a `SPPacket`
|
/// - `command` was not passed to another consuming function, e.g. to create a [SPPacket]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_command_free(command: *mut SPCommand) {
|
pub unsafe extern "C" fn sp_command_free(command: *mut SPCommand) {
|
||||||
|
assert!(!command.is_null());
|
||||||
_ = Box::from_raw(command);
|
_ = Box::from_raw(command);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! C functions for interacting with `SPConnection`s
|
//! C functions for interacting with [SPConnection]s
|
||||||
//!
|
//!
|
||||||
//! prefix `sp_connection_`
|
//! prefix `sp_connection_`
|
||||||
|
|
||||||
|
@ -18,13 +18,13 @@ use crate::{SPCommand, SPPacket};
|
||||||
/// ```
|
/// ```
|
||||||
pub struct SPConnection(pub(crate) servicepoint::Connection);
|
pub struct SPConnection(pub(crate) servicepoint::Connection);
|
||||||
|
|
||||||
/// Creates a new instance of `SPConnection`.
|
/// Creates a new instance of [SPConnection].
|
||||||
///
|
///
|
||||||
/// returns: NULL if connection fails, or connected instance
|
/// returns: NULL if connection fails, or connected instance
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Bad string encoding
|
/// - when `host` is null or an invalid host
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
@ -36,6 +36,7 @@ pub struct SPConnection(pub(crate) servicepoint::Connection);
|
||||||
pub unsafe extern "C" fn sp_connection_open(
|
pub unsafe extern "C" fn sp_connection_open(
|
||||||
host: *const c_char,
|
host: *const c_char,
|
||||||
) -> *mut SPConnection {
|
) -> *mut SPConnection {
|
||||||
|
assert!(!host.is_null());
|
||||||
let host = CStr::from_ptr(host).to_str().expect("Bad encoding");
|
let host = CStr::from_ptr(host).to_str().expect("Bad encoding");
|
||||||
let connection = match servicepoint::Connection::open(host) {
|
let connection = match servicepoint::Connection::open(host) {
|
||||||
Err(_) => return null_mut(),
|
Err(_) => return null_mut(),
|
||||||
|
@ -45,59 +46,78 @@ pub unsafe extern "C" fn sp_connection_open(
|
||||||
Box::into_raw(Box::new(SPConnection(connection)))
|
Box::into_raw(Box::new(SPConnection(connection)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a `SPPacket` to the display using the `SPConnection`.
|
/// Sends a [SPPacket] to the display using the [SPConnection].
|
||||||
///
|
///
|
||||||
/// The passed `packet` gets consumed.
|
/// The passed `packet` gets consumed.
|
||||||
///
|
///
|
||||||
/// returns: true in case of success
|
/// returns: true in case of success
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `connection` is NULL
|
||||||
|
/// - when `packet` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `connection` points to a valid instance of `SPConnection`
|
/// - `connection` points to a valid instance of [SPConnection]
|
||||||
/// - `packet` points to a valid instance of `SPPacket`
|
/// - `packet` points to a valid instance of [SPPacket]
|
||||||
/// - `packet` is not used concurrently or after this call
|
/// - `packet` is not used concurrently or after this call
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_connection_send_packet(
|
pub unsafe extern "C" fn sp_connection_send_packet(
|
||||||
connection: *const SPConnection,
|
connection: *const SPConnection,
|
||||||
packet: *mut SPPacket,
|
packet: *mut SPPacket,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
assert!(!connection.is_null());
|
||||||
|
assert!(!packet.is_null());
|
||||||
let packet = Box::from_raw(packet);
|
let packet = Box::from_raw(packet);
|
||||||
(*connection).0.send((*packet).0).is_ok()
|
(*connection).0.send((*packet).0).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a `SPCommand` to the display using the `SPConnection`.
|
/// Sends a [SPCommand] to the display using the [SPConnection].
|
||||||
///
|
///
|
||||||
/// The passed `command` gets consumed.
|
/// The passed `command` gets consumed.
|
||||||
///
|
///
|
||||||
/// returns: true in case of success
|
/// returns: true in case of success
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `connection` is NULL
|
||||||
|
/// - when `command` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `connection` points to a valid instance of `SPConnection`
|
/// - `connection` points to a valid instance of [SPConnection]
|
||||||
/// - `command` points to a valid instance of `SPPacket`
|
/// - `command` points to a valid instance of [SPPacket]
|
||||||
/// - `command` is not used concurrently or after this call
|
/// - `command` is not used concurrently or after this call
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_connection_send_command(
|
pub unsafe extern "C" fn sp_connection_send_command(
|
||||||
connection: *const SPConnection,
|
connection: *const SPConnection,
|
||||||
command: *mut SPCommand,
|
command: *mut SPCommand,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
assert!(!connection.is_null());
|
||||||
|
assert!(!command.is_null());
|
||||||
let command = (*Box::from_raw(command)).0;
|
let command = (*Box::from_raw(command)).0;
|
||||||
(*connection).0.send(command).is_ok()
|
(*connection).0.send(command).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Closes and deallocates a `SPConnection`.
|
/// Closes and deallocates a [SPConnection].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `connection` is NULL
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `connection` points to a valid `SPConnection`
|
/// - `connection` points to a valid [SPConnection]
|
||||||
/// - `connection` is not used concurrently or after this call
|
/// - `connection` is not used concurrently or after this call
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_connection_free(connection: *mut SPConnection) {
|
pub unsafe extern "C" fn sp_connection_free(connection: *mut SPConnection) {
|
||||||
|
assert!(!connection.is_null());
|
||||||
_ = Box::from_raw(connection);
|
_ = Box::from_raw(connection);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
//! C functions for interacting with `SPCp437Grid`s
|
//! C functions for interacting with [SPCp437Grid]s
|
||||||
//!
|
//!
|
||||||
//! prefix `sp_cp437_grid_`
|
//! prefix `sp_cp437_grid_`
|
||||||
|
|
||||||
|
use std::ptr::NonNull;
|
||||||
use crate::SPByteSlice;
|
use crate::SPByteSlice;
|
||||||
use servicepoint::{DataRef, Grid};
|
use servicepoint::{DataRef, Grid};
|
||||||
|
|
||||||
|
@ -25,9 +26,9 @@ impl Clone for SPCp437Grid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `SPCp437Grid` with the specified dimensions.
|
/// Creates a new [SPCp437Grid] with the specified dimensions.
|
||||||
///
|
///
|
||||||
/// returns: `SPCp437Grid` initialized to 0.
|
/// returns: [SPCp437Grid] initialized to 0. Will never return NULL.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
@ -39,19 +40,21 @@ impl Clone for SPCp437Grid {
|
||||||
pub unsafe extern "C" fn sp_cp437_grid_new(
|
pub unsafe extern "C" fn sp_cp437_grid_new(
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
) -> *mut SPCp437Grid {
|
) -> NonNull<SPCp437Grid> {
|
||||||
Box::into_raw(Box::new(SPCp437Grid(servicepoint::Cp437Grid::new(
|
let result = Box::new(SPCp437Grid(
|
||||||
width, height,
|
servicepoint::Cp437Grid::new(width, height),
|
||||||
))))
|
));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a `SPCp437Grid` with the specified dimensions from the provided data.
|
/// Loads a [SPCp437Grid] with the specified dimensions from the provided data.
|
||||||
///
|
///
|
||||||
/// Will never return NULL.
|
/// Will never return NULL.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When the provided `data_length` is not sufficient for the `height` and `width`
|
/// - when `data` is NULL
|
||||||
|
/// - when the provided `data_length` does not match `height` and `width`
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
@ -67,43 +70,56 @@ pub unsafe extern "C" fn sp_cp437_grid_load(
|
||||||
height: usize,
|
height: usize,
|
||||||
data: *const u8,
|
data: *const u8,
|
||||||
data_length: usize,
|
data_length: usize,
|
||||||
) -> *mut SPCp437Grid {
|
) -> NonNull<SPCp437Grid> {
|
||||||
|
assert!(data.is_null());
|
||||||
let data = std::slice::from_raw_parts(data, data_length);
|
let data = std::slice::from_raw_parts(data, data_length);
|
||||||
Box::into_raw(Box::new(SPCp437Grid(servicepoint::Cp437Grid::load(
|
let result = Box::new(SPCp437Grid(
|
||||||
width, height, data,
|
servicepoint::Cp437Grid::load(width, height, data),
|
||||||
))))
|
));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clones a `SPCp437Grid`.
|
/// Clones a [SPCp437Grid].
|
||||||
///
|
///
|
||||||
/// Will never return NULL.
|
/// Will never return NULL.
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `cp437_grid` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
/// - `cp437_grid` points to a valid [SPCp437Grid]
|
||||||
/// - `cp437_grid` is not written to concurrently
|
/// - `cp437_grid` is not written to concurrently
|
||||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_cp437_grid_free`.
|
/// by explicitly calling `sp_cp437_grid_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_cp437_grid_clone(
|
pub unsafe extern "C" fn sp_cp437_grid_clone(
|
||||||
cp437_grid: *const SPCp437Grid,
|
cp437_grid: *const SPCp437Grid,
|
||||||
) -> *mut SPCp437Grid {
|
) -> NonNull<SPCp437Grid> {
|
||||||
Box::into_raw(Box::new((*cp437_grid).clone()))
|
assert!(!cp437_grid.is_null());
|
||||||
|
let result = Box::new((*cp437_grid).clone());
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deallocates a `SPCp437Grid`.
|
/// Deallocates a [SPCp437Grid].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `cp437_grid` is NULL
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
/// - `cp437_grid` points to a valid [SPCp437Grid]
|
||||||
/// - `cp437_grid` is not used concurrently or after cp437_grid call
|
/// - `cp437_grid` is not used concurrently or after cp437_grid call
|
||||||
/// - `cp437_grid` was not passed to another consuming function, e.g. to create a `SPCommand`
|
/// - `cp437_grid` was not passed to another consuming function, e.g. to create a [SPCommand]
|
||||||
#[no_mangle]
|
#[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());
|
||||||
_ = Box::from_raw(cp437_grid);
|
_ = Box::from_raw(cp437_grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,13 +132,14 @@ pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) {
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When accessing `x` or `y` out of bounds.
|
/// - when `cp437_grid` is NULL
|
||||||
|
/// - when accessing `x` or `y` out of bounds
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
/// - `cp437_grid` points to a valid [SPCp437Grid]
|
||||||
/// - `cp437_grid` is not written to concurrently
|
/// - `cp437_grid` is not written to concurrently
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_cp437_grid_get(
|
pub unsafe extern "C" fn sp_cp437_grid_get(
|
||||||
|
@ -130,10 +147,11 @@ pub unsafe extern "C" fn sp_cp437_grid_get(
|
||||||
x: usize,
|
x: usize,
|
||||||
y: usize,
|
y: usize,
|
||||||
) -> u8 {
|
) -> u8 {
|
||||||
|
assert!(!cp437_grid.is_null());
|
||||||
(*cp437_grid).0.get(x, y)
|
(*cp437_grid).0.get(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the value of the specified position in the `SPCp437Grid`.
|
/// Sets the value of the specified position in the [SPCp437Grid].
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
|
@ -145,13 +163,14 @@ pub unsafe extern "C" fn sp_cp437_grid_get(
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When accessing `x` or `y` out of bounds.
|
/// - when `cp437_grid` is NULL
|
||||||
|
/// - when accessing `x` or `y` out of bounds
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `cp437_grid` points to a valid `SPBitVec`
|
/// - `cp437_grid` points to a valid [SPBitVec]
|
||||||
/// - `cp437_grid` is not written to or read from concurrently
|
/// - `cp437_grid` is not written to or read from concurrently
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_cp437_grid_set(
|
pub unsafe extern "C" fn sp_cp437_grid_set(
|
||||||
|
@ -160,84 +179,104 @@ pub unsafe extern "C" fn sp_cp437_grid_set(
|
||||||
y: usize,
|
y: usize,
|
||||||
value: u8,
|
value: u8,
|
||||||
) {
|
) {
|
||||||
|
assert!(!cp437_grid.is_null());
|
||||||
(*cp437_grid).0.set(x, y, value);
|
(*cp437_grid).0.set(x, y, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the value of all cells in the `SPCp437Grid`.
|
/// Sets the value of all cells in the [SPCp437Grid].
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `cp437_grid`: instance to write to
|
/// - `cp437_grid`: instance to write to
|
||||||
/// - `value`: the value to set all cells to
|
/// - `value`: the value to set all cells to
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `cp437_grid` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
/// - `cp437_grid` points to a valid [SPCp437Grid]
|
||||||
/// - `cp437_grid` is not written to or read from concurrently
|
/// - `cp437_grid` is not written to or read from concurrently
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_cp437_grid_fill(
|
pub unsafe extern "C" fn sp_cp437_grid_fill(
|
||||||
cp437_grid: *mut SPCp437Grid,
|
cp437_grid: *mut SPCp437Grid,
|
||||||
value: u8,
|
value: u8,
|
||||||
) {
|
) {
|
||||||
|
assert!(!cp437_grid.is_null());
|
||||||
(*cp437_grid).0.fill(value);
|
(*cp437_grid).0.fill(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the width of the `SPCp437Grid` instance.
|
/// Gets the width of the [SPCp437Grid] instance.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `cp437_grid`: instance to read from
|
/// - `cp437_grid`: instance to read from
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `cp437_grid` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
/// - `cp437_grid` points to a valid [SPCp437Grid]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_cp437_grid_width(
|
pub unsafe extern "C" fn sp_cp437_grid_width(
|
||||||
cp437_grid: *const SPCp437Grid,
|
cp437_grid: *const SPCp437Grid,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
|
assert!(!cp437_grid.is_null());
|
||||||
(*cp437_grid).0.width()
|
(*cp437_grid).0.width()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the height of the `SPCp437Grid` instance.
|
/// Gets the height of the [SPCp437Grid] instance.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `cp437_grid`: instance to read from
|
/// - `cp437_grid`: instance to read from
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `cp437_grid` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
/// - `cp437_grid` points to a valid [SPCp437Grid]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_cp437_grid_height(
|
pub unsafe extern "C" fn sp_cp437_grid_height(
|
||||||
cp437_grid: *const SPCp437Grid,
|
cp437_grid: *const SPCp437Grid,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
|
assert!(!cp437_grid.is_null());
|
||||||
(*cp437_grid).0.height()
|
(*cp437_grid).0.height()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an unsafe reference to the data of the `SPCp437Grid` instance.
|
/// Gets an unsafe reference to the data of the [SPCp437Grid] instance.
|
||||||
///
|
///
|
||||||
/// Will never return NULL.
|
/// Will never return NULL.
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `cp437_grid` is NULL
|
||||||
|
///
|
||||||
/// ## Safety
|
/// ## Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
/// - `cp437_grid` points to a valid [SPCp437Grid]
|
||||||
/// - the returned memory range is never accessed after the passed `SPCp437Grid` has been freed
|
/// - the returned memory range is never accessed after the passed [SPCp437Grid] has been freed
|
||||||
/// - the returned memory range is never accessed concurrently, either via the `SPCp437Grid` or directly
|
/// - the returned memory range is never accessed concurrently, either via the [SPCp437Grid] or directly
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_cp437_grid_unsafe_data_ref(
|
pub unsafe extern "C" fn sp_cp437_grid_unsafe_data_ref(
|
||||||
cp437_grid: *mut SPCp437Grid,
|
cp437_grid: *mut SPCp437Grid,
|
||||||
) -> SPByteSlice {
|
) -> SPByteSlice {
|
||||||
let data = (*cp437_grid).0.data_ref_mut();
|
let data = (*cp437_grid).0.data_ref_mut();
|
||||||
SPByteSlice {
|
SPByteSlice {
|
||||||
start: data.as_mut_ptr_range().start,
|
start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
|
||||||
length: data.len(),
|
length: data.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
//! if (connection == NULL)
|
//! if (connection == NULL)
|
||||||
//! return 1;
|
//! return 1;
|
||||||
//!
|
//!
|
||||||
//! SPPixelGrid *pixels = sp_pixel_grid_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
|
//! SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
|
||||||
//! sp_pixel_grid_fill(pixels, true);
|
//! sp_bitmap_fill(pixels, true);
|
||||||
//!
|
//!
|
||||||
//! SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
|
//! SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
|
||||||
//! while (sp_connection_send_command(connection, sp_command_clone(command)));
|
//! while (sp_connection_send_command(connection, sp_command_clone(command)));
|
||||||
|
@ -25,7 +25,8 @@
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
pub use crate::bit_vec::*;
|
pub use crate::bitvec::*;
|
||||||
|
pub use crate::bitmap::*;
|
||||||
pub use crate::brightness_grid::*;
|
pub use crate::brightness_grid::*;
|
||||||
pub use crate::byte_slice::*;
|
pub use crate::byte_slice::*;
|
||||||
pub use crate::command::*;
|
pub use crate::command::*;
|
||||||
|
@ -33,9 +34,9 @@ pub use crate::connection::*;
|
||||||
pub use crate::constants::*;
|
pub use crate::constants::*;
|
||||||
pub use crate::cp437_grid::*;
|
pub use crate::cp437_grid::*;
|
||||||
pub use crate::packet::*;
|
pub use crate::packet::*;
|
||||||
pub use crate::pixel_grid::*;
|
|
||||||
|
|
||||||
mod bit_vec;
|
mod bitvec;
|
||||||
|
mod bitmap;
|
||||||
mod brightness_grid;
|
mod brightness_grid;
|
||||||
mod byte_slice;
|
mod byte_slice;
|
||||||
mod command;
|
mod command;
|
||||||
|
@ -43,4 +44,3 @@ mod connection;
|
||||||
mod constants;
|
mod constants;
|
||||||
mod cp437_grid;
|
mod cp437_grid;
|
||||||
mod packet;
|
mod packet;
|
||||||
mod pixel_grid;
|
|
||||||
|
|
|
@ -1,53 +1,63 @@
|
||||||
//! C functions for interacting with `SPPacket`s
|
//! C functions for interacting with [SPPacket]s
|
||||||
//!
|
//!
|
||||||
//! prefix `sp_packet_`
|
//! prefix `sp_packet_`
|
||||||
|
|
||||||
use std::ptr::null_mut;
|
use std::ptr::{null_mut, NonNull};
|
||||||
|
|
||||||
use crate::SPCommand;
|
use crate::SPCommand;
|
||||||
|
|
||||||
/// The raw packet
|
/// The raw packet
|
||||||
pub struct SPPacket(pub(crate) servicepoint::packet::Packet);
|
pub struct SPPacket(pub(crate) servicepoint::packet::Packet);
|
||||||
|
|
||||||
/// Turns a `SPCommand` into a `SPPacket`.
|
/// Turns a [SPCommand] into a [SPPacket].
|
||||||
/// The `SPCommand` gets consumed.
|
/// The [SPCommand] gets consumed.
|
||||||
///
|
///
|
||||||
/// Will never return NULL.
|
/// Will never return NULL.
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `command` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `SPCommand` points to a valid instance of `SPCommand`
|
/// - [SPCommand] points to a valid instance of [SPCommand]
|
||||||
/// - `SPCommand` is not used concurrently or after this call
|
/// - [SPCommand] is not used concurrently or after this call
|
||||||
/// - the returned `SPPacket` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPPacket] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_packet_free`.
|
/// by explicitly calling `sp_packet_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_packet_from_command(
|
pub unsafe extern "C" fn sp_packet_from_command(
|
||||||
command: *mut SPCommand,
|
command: *mut SPCommand,
|
||||||
) -> *mut SPPacket {
|
) -> NonNull<SPPacket> {
|
||||||
|
assert!(!command.is_null());
|
||||||
let command = *Box::from_raw(command);
|
let command = *Box::from_raw(command);
|
||||||
let packet = SPPacket(command.0.into());
|
let result = Box::new(SPPacket(command.0.into()));
|
||||||
Box::into_raw(Box::new(packet))
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to load a `SPPacket` from the passed array with the specified length.
|
/// Tries to load a [SPPacket] from the passed array with the specified length.
|
||||||
///
|
///
|
||||||
/// returns: NULL in case of an error, pointer to the allocated packet otherwise
|
/// returns: NULL in case of an error, pointer to the allocated packet otherwise
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `data` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `data` points to a valid memory region of at least `length` bytes
|
/// - `data` points to a valid memory region of at least `length` bytes
|
||||||
/// - `data` is not written to concurrently
|
/// - `data` is not written to concurrently
|
||||||
/// - the returned `SPPacket` instance is freed in some way, either by using a consuming function or
|
/// - the returned [SPPacket] instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_packet_free`.
|
/// by explicitly calling `sp_packet_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_packet_try_load(
|
pub unsafe extern "C" fn sp_packet_try_load(
|
||||||
data: *const u8,
|
data: *const u8,
|
||||||
length: usize,
|
length: usize,
|
||||||
) -> *mut SPPacket {
|
) -> *mut SPPacket {
|
||||||
|
assert!(!data.is_null());
|
||||||
let data = std::slice::from_raw_parts(data, length);
|
let data = std::slice::from_raw_parts(data, length);
|
||||||
match servicepoint::packet::Packet::try_from(data) {
|
match servicepoint::packet::Packet::try_from(data) {
|
||||||
Err(_) => null_mut(),
|
Err(_) => null_mut(),
|
||||||
|
@ -55,34 +65,45 @@ pub unsafe extern "C" fn sp_packet_try_load(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clones a `SPPacket`.
|
/// Clones a [SPPacket].
|
||||||
///
|
///
|
||||||
/// Will never return NULL.
|
/// Will never return NULL.
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `packet` is NULL
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `packet` points to a valid `SPPacket`
|
/// - `packet` points to a valid [SPPacket]
|
||||||
/// - `packet` is not written to concurrently
|
/// - `packet` is not written to concurrently
|
||||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||||
/// by explicitly calling `sp_packet_free`.
|
/// by explicitly calling `sp_packet_free`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_packet_clone(
|
pub unsafe extern "C" fn sp_packet_clone(
|
||||||
packet: *const SPPacket,
|
packet: *const SPPacket,
|
||||||
) -> *mut SPPacket {
|
) -> NonNull<SPPacket> {
|
||||||
Box::into_raw(Box::new(SPPacket((*packet).0.clone())))
|
assert!(!packet.is_null());
|
||||||
|
let result = Box::new(SPPacket((*packet).0.clone()));
|
||||||
|
NonNull::from(Box::leak(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deallocates a `SPPacket`.
|
/// Deallocates a [SPPacket].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - when `sp_packet_free` is NULL
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller has to make sure that:
|
/// The caller has to make sure that:
|
||||||
///
|
///
|
||||||
/// - `packet` points to a valid `SPPacket`
|
/// - `packet` points to a valid [SPPacket]
|
||||||
/// - `packet` is not used concurrently or after this call
|
/// - `packet` is not used concurrently or after this call
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sp_packet_free(packet: *mut SPPacket) {
|
pub unsafe extern "C" fn sp_packet_free(packet: *mut SPPacket) {
|
||||||
|
assert!(!packet.is_null());
|
||||||
_ = Box::from_raw(packet)
|
_ = Box::from_raw(packet)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,248 +0,0 @@
|
||||||
//! C functions for interacting with `SPPixelGrid`s
|
|
||||||
//!
|
|
||||||
//! prefix `sp_pixel_grid_`
|
|
||||||
|
|
||||||
use servicepoint::{DataRef, Grid};
|
|
||||||
|
|
||||||
use crate::byte_slice::SPByteSlice;
|
|
||||||
|
|
||||||
/// A grid of pixels.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```C
|
|
||||||
/// Cp437Grid grid = sp_pixel_grid_new(8, 3);
|
|
||||||
/// sp_pixel_grid_fill(grid, true);
|
|
||||||
/// sp_pixel_grid_set(grid, 0, 0, false);
|
|
||||||
/// sp_pixel_grid_free(grid);
|
|
||||||
/// ```
|
|
||||||
pub struct SPPixelGrid(pub(crate) servicepoint::PixelGrid);
|
|
||||||
|
|
||||||
/// Creates a new `SPPixelGrid` with the specified dimensions.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// - `width`: size in pixels in x-direction
|
|
||||||
/// - `height`: size in pixels in y-direction
|
|
||||||
///
|
|
||||||
/// returns: `SPPixelGrid` initialized to all pixels off. Will never return NULL.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// - when the width is not dividable by 8
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The caller has to make sure that:
|
|
||||||
///
|
|
||||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
|
||||||
/// by explicitly calling `sp_pixel_grid_free`.
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_pixel_grid_new(
|
|
||||||
width: usize,
|
|
||||||
height: usize,
|
|
||||||
) -> *mut SPPixelGrid {
|
|
||||||
Box::into_raw(Box::new(SPPixelGrid(servicepoint::PixelGrid::new(
|
|
||||||
width, height,
|
|
||||||
))))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Loads a `SPPixelGrid` with the specified dimensions from the provided data.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// - `width`: size in pixels in x-direction
|
|
||||||
/// - `height`: size in pixels in y-direction
|
|
||||||
///
|
|
||||||
/// returns: `SPPixelGrid` that contains a copy of the provided data. Will never return NULL.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// - when the dimensions and data size do not match exactly.
|
|
||||||
/// - when the width is not dividable by 8
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The caller has to make sure that:
|
|
||||||
///
|
|
||||||
/// - `data` points to a valid memory location of at least `data_length` bytes in size.
|
|
||||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
|
||||||
/// by explicitly calling `sp_pixel_grid_free`.
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_pixel_grid_load(
|
|
||||||
width: usize,
|
|
||||||
height: usize,
|
|
||||||
data: *const u8,
|
|
||||||
data_length: usize,
|
|
||||||
) -> *mut SPPixelGrid {
|
|
||||||
let data = std::slice::from_raw_parts(data, data_length);
|
|
||||||
Box::into_raw(Box::new(SPPixelGrid(servicepoint::PixelGrid::load(
|
|
||||||
width, height, data,
|
|
||||||
))))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clones a `SPPixelGrid`.
|
|
||||||
///
|
|
||||||
/// Will never return NULL.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The caller has to make sure that:
|
|
||||||
///
|
|
||||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
|
||||||
/// - `pixel_grid` is not written to concurrently
|
|
||||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
|
||||||
/// by explicitly calling `sp_pixel_grid_free`.
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_pixel_grid_clone(
|
|
||||||
pixel_grid: *const SPPixelGrid,
|
|
||||||
) -> *mut SPPixelGrid {
|
|
||||||
Box::into_raw(Box::new(SPPixelGrid((*pixel_grid).0.clone())))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deallocates a `SPPixelGrid`.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The caller has to make sure that:
|
|
||||||
///
|
|
||||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
|
||||||
/// - `pixel_grid` is not used concurrently or after pixel_grid call
|
|
||||||
/// - `pixel_grid` was not passed to another consuming function, e.g. to create a `SPCommand`
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_pixel_grid_free(pixel_grid: *mut SPPixelGrid) {
|
|
||||||
_ = Box::from_raw(pixel_grid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the current value at the specified position in the `SPPixelGrid`.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// - `pixel_grid`: instance to read from
|
|
||||||
/// - `x` and `y`: position of the cell to read
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// When accessing `x` or `y` out of bounds.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The caller has to make sure that:
|
|
||||||
///
|
|
||||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
|
||||||
/// - `pixel_grid` is not written to concurrently
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_pixel_grid_get(
|
|
||||||
pixel_grid: *const SPPixelGrid,
|
|
||||||
x: usize,
|
|
||||||
y: usize,
|
|
||||||
) -> bool {
|
|
||||||
(*pixel_grid).0.get(x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the value of the specified position in the `SPPixelGrid`.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// - `pixel_grid`: instance to write to
|
|
||||||
/// - `x` and `y`: position of the cell
|
|
||||||
/// - `value`: the value to write to the cell
|
|
||||||
///
|
|
||||||
/// returns: old value of the cell
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// When accessing `x` or `y` out of bounds.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The caller has to make sure that:
|
|
||||||
///
|
|
||||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
|
||||||
/// - `pixel_grid` is not written to or read from concurrently
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_pixel_grid_set(
|
|
||||||
pixel_grid: *mut SPPixelGrid,
|
|
||||||
x: usize,
|
|
||||||
y: usize,
|
|
||||||
value: bool,
|
|
||||||
) {
|
|
||||||
(*pixel_grid).0.set(x, y, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the state of all pixels in the `SPPixelGrid`.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// - `pixel_grid`: instance to write to
|
|
||||||
/// - `value`: the value to set all pixels to
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The caller has to make sure that:
|
|
||||||
///
|
|
||||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
|
||||||
/// - `pixel_grid` is not written to or read from concurrently
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_pixel_grid_fill(
|
|
||||||
pixel_grid: *mut SPPixelGrid,
|
|
||||||
value: bool,
|
|
||||||
) {
|
|
||||||
(*pixel_grid).0.fill(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the width in pixels of the `SPPixelGrid` instance.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// - `pixel_grid`: instance to read from
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The caller has to make sure that:
|
|
||||||
///
|
|
||||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_pixel_grid_width(
|
|
||||||
pixel_grid: *const SPPixelGrid,
|
|
||||||
) -> usize {
|
|
||||||
(*pixel_grid).0.width()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the height in pixels of the `SPPixelGrid` instance.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// - `pixel_grid`: instance to read from
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The caller has to make sure that:
|
|
||||||
///
|
|
||||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_pixel_grid_height(
|
|
||||||
pixel_grid: *const SPPixelGrid,
|
|
||||||
) -> usize {
|
|
||||||
(*pixel_grid).0.height()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets an unsafe reference to the data of the `SPPixelGrid` instance.
|
|
||||||
///
|
|
||||||
/// ## Safety
|
|
||||||
///
|
|
||||||
/// The caller has to make sure that:
|
|
||||||
///
|
|
||||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
|
||||||
/// - the returned memory range is never accessed after the passed `SPPixelGrid` has been freed
|
|
||||||
/// - the returned memory range is never accessed concurrently, either via the `SPPixelGrid` or directly
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_pixel_grid_unsafe_data_ref(
|
|
||||||
pixel_grid: *mut SPPixelGrid,
|
|
||||||
) -> SPByteSlice {
|
|
||||||
let data = (*pixel_grid).0.data_ref_mut();
|
|
||||||
SPByteSlice {
|
|
||||||
start: data.as_mut_ptr_range().start,
|
|
||||||
length: data.len(),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,8 +13,8 @@ test = false
|
||||||
csbindgen = "1.9.3"
|
csbindgen = "1.9.3"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
servicepoint_binding_c = { version = "0.9.1", path = "../servicepoint_binding_c" }
|
servicepoint_binding_c = { version = "0.10.0", path = "../servicepoint_binding_c" }
|
||||||
servicepoint = { version = "0.9.1", path = "../servicepoint" }
|
servicepoint = { version = "0.10.0", path = "../servicepoint" }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -11,7 +11,7 @@ using ServicePoint;
|
||||||
|
|
||||||
// using statement calls Dispose() on scope exit, which frees unmanaged instances
|
// using statement calls Dispose() on scope exit, which frees unmanaged instances
|
||||||
using var connection = Connection.Open("127.0.0.1:2342");
|
using var connection = Connection.Open("127.0.0.1:2342");
|
||||||
using var pixels = PixelGrid.New(Constants.PixelWidth, Constants.PixelHeight);
|
using var pixels = Bitmap.New(Constants.PixelWidth, Constants.PixelHeight);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,7 +8,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
return new BitVec(NativeMethods.sp_bit_vec_new((nuint)size));
|
return new BitVec(NativeMethods.sp_bitvec_new((nuint)size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
|
||||||
{
|
{
|
||||||
fixed (byte* bytesPtr = bytes)
|
fixed (byte* bytesPtr = bytes)
|
||||||
{
|
{
|
||||||
return new BitVec(NativeMethods.sp_bit_vec_load(bytesPtr, (nuint)bytes.Length));
|
return new BitVec(NativeMethods.sp_bitvec_load(bytesPtr, (nuint)bytes.Length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
return new BitVec(NativeMethods.sp_bit_vec_clone(Instance));
|
return new BitVec(NativeMethods.sp_bitvec_clone(Instance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,14 +37,14 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
return NativeMethods.sp_bit_vec_get(Instance, (nuint)index);
|
return NativeMethods.sp_bitvec_get(Instance, (nuint)index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
NativeMethods.sp_bit_vec_set(Instance, (nuint)index, value);
|
NativeMethods.sp_bitvec_set(Instance, (nuint)index, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
NativeMethods.sp_bit_vec_fill(Instance, value);
|
NativeMethods.sp_bitvec_fill(Instance, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
return (int)NativeMethods.sp_bit_vec_len(Instance);
|
return (int)NativeMethods.sp_bitvec_len(Instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
var slice = NativeMethods.sp_bit_vec_unsafe_data_ref(Instance);
|
var slice = NativeMethods.sp_bitvec_unsafe_data_ref(Instance);
|
||||||
return new Span<byte>(slice.start, (int)slice.length);
|
return new Span<byte>(slice.start, (int)slice.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,5 +84,5 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private protected override unsafe void Free() => NativeMethods.sp_bit_vec_free(Instance);
|
private protected override unsafe void Free() => NativeMethods.sp_bitvec_free(Instance);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,33 +2,33 @@ using ServicePoint.BindGen;
|
||||||
|
|
||||||
namespace ServicePoint;
|
namespace ServicePoint;
|
||||||
|
|
||||||
public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
|
public sealed class Bitmap : SpNativeInstance<BindGen.Bitmap>
|
||||||
{
|
{
|
||||||
public static PixelGrid New(int width, int height)
|
public static Bitmap New(int width, int height)
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
return new PixelGrid(NativeMethods.sp_pixel_grid_new((nuint)width, (nuint)height));
|
return new Bitmap(NativeMethods.sp_bitmap_new((nuint)width, (nuint)height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PixelGrid Load(int width, int height, Span<byte> bytes)
|
public static Bitmap Load(int width, int height, Span<byte> bytes)
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
fixed (byte* bytesPtr = bytes)
|
fixed (byte* bytesPtr = bytes)
|
||||||
{
|
{
|
||||||
return new PixelGrid(NativeMethods.sp_pixel_grid_load((nuint)width, (nuint)height, bytesPtr,
|
return new Bitmap(NativeMethods.sp_bitmap_load((nuint)width, (nuint)height, bytesPtr,
|
||||||
(nuint)bytes.Length));
|
(nuint)bytes.Length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PixelGrid Clone()
|
public Bitmap Clone()
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
return new PixelGrid(NativeMethods.sp_pixel_grid_clone(Instance));
|
return new Bitmap(NativeMethods.sp_bitmap_clone(Instance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,14 +38,14 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
return NativeMethods.sp_pixel_grid_get(Instance, (nuint)x, (nuint)y);
|
return NativeMethods.sp_bitmap_get(Instance, (nuint)x, (nuint)y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
NativeMethods.sp_pixel_grid_set(Instance, (nuint)x, (nuint)y, value);
|
NativeMethods.sp_bitmap_set(Instance, (nuint)x, (nuint)y, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
NativeMethods.sp_pixel_grid_fill(Instance, value);
|
NativeMethods.sp_bitmap_fill(Instance, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
return (int)NativeMethods.sp_pixel_grid_width(Instance);
|
return (int)NativeMethods.sp_bitmap_width(Instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
return (int)NativeMethods.sp_pixel_grid_height(Instance);
|
return (int)NativeMethods.sp_bitmap_height(Instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,15 +86,15 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
var slice = NativeMethods.sp_pixel_grid_unsafe_data_ref(Instance);
|
var slice = NativeMethods.sp_bitmap_unsafe_data_ref(Instance);
|
||||||
return new Span<byte>(slice.start, (int)slice.length);
|
return new Span<byte>(slice.start, (int)slice.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe PixelGrid(BindGen.PixelGrid* instance) : base(instance)
|
private unsafe Bitmap(BindGen.Bitmap* instance) : base(instance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private protected override unsafe void Free() => NativeMethods.sp_pixel_grid_free(Instance);
|
private protected override unsafe void Free() => NativeMethods.sp_bitmap_free(Instance);
|
||||||
}
|
}
|
|
@ -105,11 +105,11 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Command BitmapLinearWin(int x, int y, PixelGrid pixelGrid, CompressionCode compression)
|
public static Command BitmapLinearWin(int x, int y, Bitmap bitmap, CompressionCode compression)
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
return new Command(NativeMethods.sp_command_bitmap_linear_win((ushort)x, (ushort)y, pixelGrid.Into(), compression));
|
return new Command(NativeMethods.sp_command_bitmap_linear_win((ushort)x, (ushort)y, bitmap.Into(), compression));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
|
using ServicePoint.BindGen;
|
||||||
|
|
||||||
namespace ServicePoint;
|
namespace ServicePoint;
|
||||||
|
|
||||||
public static class Constants
|
public static class Constants
|
||||||
{
|
{
|
||||||
/// size of a single tile in one dimension
|
/// size of a single tile in one dimension
|
||||||
public const int TileSize = 8;
|
public const nuint TileSize = NativeMethods.SP_TILE_SIZE;
|
||||||
|
|
||||||
/// tile count in the x-direction
|
/// tile count in the x-direction
|
||||||
public const int TileWidth = 56;
|
public const nuint TileWidth = NativeMethods.SP_TILE_WIDTH;
|
||||||
|
|
||||||
/// tile count in the y-direction
|
/// tile count in the y-direction
|
||||||
public const int TileHeight = 20;
|
public const nuint TileHeight = NativeMethods.SP_TILE_SIZE;
|
||||||
|
|
||||||
/// screen width in pixels
|
/// screen width in pixels
|
||||||
public const int PixelWidth = TileWidth * TileSize;
|
public const nuint PixelWidth = TileWidth * TileSize;
|
||||||
|
|
||||||
/// screen height in pixels
|
/// screen height in pixels
|
||||||
public const int PixelHeight = TileHeight * TileSize;
|
public const nuint PixelHeight = TileHeight * TileSize;
|
||||||
|
|
||||||
/// pixel count on whole screen
|
/// pixel count on whole screen
|
||||||
public const int PixelCount = PixelWidth * PixelHeight;
|
public const nuint PixelCount = PixelWidth * PixelHeight;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PackageId>ServicePoint</PackageId>
|
<PackageId>ServicePoint</PackageId>
|
||||||
<Version>0.9.1</Version>
|
<Version>0.10.0</Version>
|
||||||
<Authors>Repository Authors</Authors>
|
<Authors>Repository Authors</Authors>
|
||||||
<Company>None</Company>
|
<Company>None</Company>
|
||||||
<Product>ServicePoint</Product>
|
<Product>ServicePoint</Product>
|
||||||
|
|
|
@ -8,8 +8,12 @@ fn main() {
|
||||||
|
|
||||||
let mut builder = csbindgen::Builder::default();
|
let mut builder = csbindgen::Builder::default();
|
||||||
|
|
||||||
for source in fs::read_dir("../servicepoint_binding_c/src").unwrap() {
|
let mut paths = fs::read_dir("../servicepoint_binding_c/src").unwrap()
|
||||||
let path = source.unwrap().path();
|
.map(|x| x.unwrap().path())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
paths.sort();
|
||||||
|
|
||||||
|
for path in paths {
|
||||||
println!("cargo:rerun-if-changed={}", path.display());
|
println!("cargo:rerun-if-changed={}", path.display());
|
||||||
builder = builder.input_extern_file(path);
|
builder = builder.input_extern_file(path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ using var connection = Connection.Open("127.0.0.1:2342");
|
||||||
connection.Send(Command.Clear().IntoPacket());
|
connection.Send(Command.Clear().IntoPacket());
|
||||||
connection.Send(Command.Brightness(128).IntoPacket());
|
connection.Send(Command.Brightness(128).IntoPacket());
|
||||||
|
|
||||||
using var pixels = PixelGrid.New(Constants.PixelWidth, Constants.PixelHeight);
|
using var pixels = Bitmap.New(Constants.PixelWidth, Constants.PixelHeight);
|
||||||
|
|
||||||
for (var offset = 0; offset < int.MaxValue; offset++)
|
for (var offset = 0; offset < int.MaxValue; offset++)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue