Merge branch 'fix-brightness'
This commit is contained in:
		
						commit
						a484e6a976
					
				
					 35 changed files with 1594 additions and 553 deletions
				
			
		
							
								
								
									
										14
									
								
								.github/workflows/rust.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/rust.yml
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -16,9 +16,17 @@ jobs:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - uses: actions/checkout@v4
 | 
					    - uses: actions/checkout@v4
 | 
				
			||||||
    - name: Build crates
 | 
					
 | 
				
			||||||
 | 
					    - name: build default features
 | 
				
			||||||
      run: cargo build --all --verbose
 | 
					      run: cargo build --all --verbose
 | 
				
			||||||
    - name: Build
 | 
					    - name: build default features -- examples
 | 
				
			||||||
      run: cargo build --examples --verbose
 | 
					      run: cargo build --examples --verbose
 | 
				
			||||||
    - name: Run tests
 | 
					    - name: test default features
 | 
				
			||||||
      run: cargo test --all --verbose
 | 
					      run: cargo test --all --verbose
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: build all features
 | 
				
			||||||
 | 
					      run: cargo build --all-features --verbose
 | 
				
			||||||
 | 
					    - name: build all features -- examples
 | 
				
			||||||
 | 
					      run: cargo build --all-features --examples --verbose
 | 
				
			||||||
 | 
					    - name: test all features
 | 
				
			||||||
 | 
					      run: cargo test --all --all-features --verbose
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,12 @@
 | 
				
			||||||
[workspace]
 | 
					[workspace]
 | 
				
			||||||
resolver = "2"
 | 
					resolver = "2"
 | 
				
			||||||
members = [
 | 
					members = [
 | 
				
			||||||
    "crates/servicepoint",
 | 
					    "crates/*",
 | 
				
			||||||
    "crates/servicepoint_binding_c",
 | 
					 | 
				
			||||||
    "crates/servicepoint_binding_cs",
 | 
					 | 
				
			||||||
    "crates/servicepoint_binding_c/examples/lang_c"
 | 
					    "crates/servicepoint_binding_c/examples/lang_c"
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[workspace.package]
 | 
					[workspace.package]
 | 
				
			||||||
version = "0.6.0"
 | 
					version = "0.7.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[workspace.lints.rust]
 | 
					[workspace.lints.rust]
 | 
				
			||||||
missing-docs = "warn"
 | 
					missing-docs = "warn"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,7 @@ flate2 = { version = "1.0", optional = true }
 | 
				
			||||||
bzip2 = { version = "0.4", optional = true }
 | 
					bzip2 = { version = "0.4", optional = true }
 | 
				
			||||||
zstd = { version = "0.13", optional = true }
 | 
					zstd = { version = "0.13", optional = true }
 | 
				
			||||||
rust-lzma = { version = "0.6.0", optional = true }
 | 
					rust-lzma = { version = "0.6.0", optional = true }
 | 
				
			||||||
 | 
					rand = { version = "0.8", optional = true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[features]
 | 
					[features]
 | 
				
			||||||
default = ["compression_lzma"]
 | 
					default = ["compression_lzma"]
 | 
				
			||||||
| 
						 | 
					@ -27,6 +28,11 @@ compression_bzip2 = ["dep:bzip2"]
 | 
				
			||||||
compression_lzma = ["dep:rust-lzma"]
 | 
					compression_lzma = ["dep:rust-lzma"]
 | 
				
			||||||
compression_zstd = ["dep:zstd"]
 | 
					compression_zstd = ["dep:zstd"]
 | 
				
			||||||
all_compressions = ["compression_zlib", "compression_bzip2", "compression_lzma", "compression_zstd"]
 | 
					all_compressions = ["compression_zlib", "compression_bzip2", "compression_lzma", "compression_zstd"]
 | 
				
			||||||
 | 
					rand = ["dep:rand"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[example]]
 | 
				
			||||||
 | 
					name = "random_brightness"
 | 
				
			||||||
 | 
					required-features = ["rand"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dev-dependencies]
 | 
					[dev-dependencies]
 | 
				
			||||||
# for examples
 | 
					# for examples
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@ In the likely case you only need one of them, you can include that one specifica
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```toml
 | 
					```toml
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
servicepoint = { version = "0.6.0", default-features = false, features = ["compression-bz"] }
 | 
					servicepoint = { version = "0.7.0", default-features = false, features = ["compression-bz"] }
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Everything else
 | 
					## Everything else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use clap::Parser;
 | 
					use clap::Parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use servicepoint::{ByteGrid, Command, Connection, Grid, Origin};
 | 
					use servicepoint::{Command, Connection, Cp437Grid, Grid, Origin};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Parser, Debug)]
 | 
					#[derive(Parser, Debug)]
 | 
				
			||||||
struct Cli {
 | 
					struct Cli {
 | 
				
			||||||
| 
						 | 
					@ -22,14 +22,18 @@ fn main() {
 | 
				
			||||||
        cli.text.push("Hello, CCCB!".to_string());
 | 
					        cli.text.push("Hello, CCCB!".to_string());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let connection = Connection::open(&cli.destination).unwrap();
 | 
					    let connection = Connection::open(&cli.destination)
 | 
				
			||||||
 | 
					        .expect("could not connect to display");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if cli.clear {
 | 
					    if cli.clear {
 | 
				
			||||||
        connection.send(Command::Clear).unwrap();
 | 
					        connection
 | 
				
			||||||
 | 
					            .send(Command::Clear)
 | 
				
			||||||
 | 
					            .expect("sending clear failed");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let max_width = cli.text.iter().map(|t| t.len()).max().unwrap();
 | 
					    let max_width = cli.text.iter().map(|t| t.len()).max().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut chars = ByteGrid::new(max_width, cli.text.len());
 | 
					    let mut chars = Cp437Grid::new(max_width, cli.text.len());
 | 
				
			||||||
    for y in 0..cli.text.len() {
 | 
					    for y in 0..cli.text.len() {
 | 
				
			||||||
        let row = &cli.text[y];
 | 
					        let row = &cli.text[y];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +44,6 @@ fn main() {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    connection
 | 
					    connection
 | 
				
			||||||
        .send(Command::Cp437Data(Origin(0, 0), chars))
 | 
					        .send(Command::Cp437Data(Origin::new(0, 0), chars))
 | 
				
			||||||
        .unwrap();
 | 
					        .expect("sending text failed");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use clap::Parser;
 | 
					use clap::Parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use servicepoint::Command::BitmapLinearWin;
 | 
					 | 
				
			||||||
use servicepoint::*;
 | 
					use servicepoint::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Parser, Debug)]
 | 
					#[derive(Parser, Debug)]
 | 
				
			||||||
| 
						 | 
					@ -13,25 +12,26 @@ struct Cli {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
    let cli = Cli::parse();
 | 
					    let cli = Cli::parse();
 | 
				
			||||||
    let connection = Connection::open(cli.destination).unwrap();
 | 
					    let connection = Connection::open(cli.destination)
 | 
				
			||||||
 | 
					        .expect("could not connect to display");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut pixels = PixelGrid::max_sized();
 | 
					    let mut pixels = PixelGrid::max_sized();
 | 
				
			||||||
    pixels.fill(true);
 | 
					    pixels.fill(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    connection
 | 
					    let command = Command::BitmapLinearWin(
 | 
				
			||||||
        .send(BitmapLinearWin(
 | 
					        Origin::new(0, 0),
 | 
				
			||||||
            Origin(0, 0),
 | 
					 | 
				
			||||||
        pixels,
 | 
					        pixels,
 | 
				
			||||||
        CompressionCode::Uncompressed,
 | 
					        CompressionCode::Uncompressed,
 | 
				
			||||||
        ))
 | 
					    );
 | 
				
			||||||
        .expect("send failed");
 | 
					    connection.send(command).expect("send failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut brightnesses = ByteGrid::new(TILE_WIDTH, TILE_HEIGHT);
 | 
					    let max_brightness = usize::from(u8::from(Brightness::MAX));
 | 
				
			||||||
 | 
					    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 = (index % u8::MAX as usize) as u8;
 | 
					        *byte = Brightness::try_from((index % max_brightness) as u8).unwrap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    connection
 | 
					    connection
 | 
				
			||||||
        .send(Command::CharBrightness(Origin(0, 0), brightnesses))
 | 
					        .send(Command::CharBrightness(Origin::new(0, 0), brightnesses))
 | 
				
			||||||
        .expect("send failed");
 | 
					        .expect("send failed");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,17 +18,17 @@ struct Cli {
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
    let cli = Cli::parse();
 | 
					    let cli = Cli::parse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let connection = Connection::open(&cli.destination).unwrap();
 | 
					    let connection = Connection::open(&cli.destination)
 | 
				
			||||||
 | 
					        .expect("could not connect to display");
 | 
				
			||||||
    let mut field = make_random_field(cli.probability);
 | 
					    let mut field = make_random_field(cli.probability);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    loop {
 | 
					    loop {
 | 
				
			||||||
        connection
 | 
					        let command = Command::BitmapLinearWin(
 | 
				
			||||||
            .send(Command::BitmapLinearWin(
 | 
					            Origin::new(0, 0),
 | 
				
			||||||
                Origin(0, 0),
 | 
					 | 
				
			||||||
            field.clone(),
 | 
					            field.clone(),
 | 
				
			||||||
            CompressionCode::Lzma,
 | 
					            CompressionCode::Lzma,
 | 
				
			||||||
            ))
 | 
					        );
 | 
				
			||||||
            .expect("could not send");
 | 
					        connection.send(command).expect("could not send");
 | 
				
			||||||
        thread::sleep(FRAME_PACING);
 | 
					        thread::sleep(FRAME_PACING);
 | 
				
			||||||
        field = iteration(field);
 | 
					        field = iteration(field);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,8 @@ struct Cli {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
    let connection = Connection::open(Cli::parse().destination).unwrap();
 | 
					    let connection = Connection::open(Cli::parse().destination)
 | 
				
			||||||
 | 
					        .expect("could not connect to display");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut pixels = PixelGrid::max_sized();
 | 
					    let mut pixels = PixelGrid::max_sized();
 | 
				
			||||||
    for x_offset in 0..usize::MAX {
 | 
					    for x_offset in 0..usize::MAX {
 | 
				
			||||||
| 
						 | 
					@ -22,13 +23,13 @@ fn main() {
 | 
				
			||||||
        for y in 0..PIXEL_HEIGHT {
 | 
					        for y in 0..PIXEL_HEIGHT {
 | 
				
			||||||
            pixels.set((y + x_offset) % PIXEL_WIDTH, y, true);
 | 
					            pixels.set((y + x_offset) % PIXEL_WIDTH, y, true);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        connection
 | 
					
 | 
				
			||||||
            .send(Command::BitmapLinearWin(
 | 
					        let command = Command::BitmapLinearWin(
 | 
				
			||||||
                Origin(0, 0),
 | 
					            Origin::new(0, 0),
 | 
				
			||||||
            pixels.clone(),
 | 
					            pixels.clone(),
 | 
				
			||||||
            CompressionCode::Lzma,
 | 
					            CompressionCode::Lzma,
 | 
				
			||||||
            ))
 | 
					        );
 | 
				
			||||||
            .unwrap();
 | 
					        connection.send(command).expect("send failed");
 | 
				
			||||||
        thread::sleep(FRAME_PACING);
 | 
					        thread::sleep(FRAME_PACING);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,8 @@ struct Cli {
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
    let cli = Cli::parse();
 | 
					    let cli = Cli::parse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let connection = Connection::open(cli.destination).unwrap();
 | 
					    let connection = Connection::open(cli.destination)
 | 
				
			||||||
 | 
					        .expect("could not connect to display");
 | 
				
			||||||
    let wait_duration = Duration::from_millis(cli.wait_ms);
 | 
					    let wait_duration = Duration::from_millis(cli.wait_ms);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // put all pixels in on state
 | 
					    // put all pixels in on state
 | 
				
			||||||
| 
						 | 
					@ -30,8 +31,11 @@ fn main() {
 | 
				
			||||||
        let mut filled_grid = PixelGrid::max_sized();
 | 
					        let mut filled_grid = PixelGrid::max_sized();
 | 
				
			||||||
        filled_grid.fill(true);
 | 
					        filled_grid.fill(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let command =
 | 
					        let command = BitmapLinearWin(
 | 
				
			||||||
            BitmapLinearWin(Origin(0, 0), filled_grid, CompressionCode::Lzma);
 | 
					            Origin::new(0, 0),
 | 
				
			||||||
 | 
					            filled_grid,
 | 
				
			||||||
 | 
					            CompressionCode::Lzma,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        connection.send(command).expect("send failed");
 | 
					        connection.send(command).expect("send failed");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,8 +52,8 @@ fn main() {
 | 
				
			||||||
        let w = rng.gen_range(min_size..=TILE_WIDTH - x);
 | 
					        let w = rng.gen_range(min_size..=TILE_WIDTH - x);
 | 
				
			||||||
        let h = rng.gen_range(min_size..=TILE_HEIGHT - y);
 | 
					        let h = rng.gen_range(min_size..=TILE_HEIGHT - y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let origin = Origin(x, y);
 | 
					        let origin = Origin::new(x, y);
 | 
				
			||||||
        let mut luma = ByteGrid::new(w, h);
 | 
					        let mut luma = BrightnessGrid::new(w, h);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for y in 0..h {
 | 
					        for y in 0..h {
 | 
				
			||||||
            for x in 0..w {
 | 
					            for x in 0..w {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,8 @@ fn main() {
 | 
				
			||||||
        Duration::from_millis(cli.time / PIXEL_WIDTH as u64),
 | 
					        Duration::from_millis(cli.time / PIXEL_WIDTH as u64),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let connection = Connection::open(cli.destination).unwrap();
 | 
					    let connection = Connection::open(cli.destination)
 | 
				
			||||||
 | 
					        .expect("could not connect to display");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut enabled_pixels = PixelGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT);
 | 
					    let mut enabled_pixels = PixelGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT);
 | 
				
			||||||
    enabled_pixels.fill(true);
 | 
					    enabled_pixels.fill(true);
 | 
				
			||||||
| 
						 | 
					@ -38,7 +39,7 @@ fn main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        connection
 | 
					        connection
 | 
				
			||||||
            .send(Command::BitmapLinearAnd(0, bit_vec, CompressionCode::Lzma))
 | 
					            .send(Command::BitmapLinearAnd(0, bit_vec, CompressionCode::Lzma))
 | 
				
			||||||
            .unwrap();
 | 
					            .expect("could not send command to display");
 | 
				
			||||||
        thread::sleep(sleep_duration);
 | 
					        thread::sleep(sleep_duration);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										111
									
								
								crates/servicepoint/src/brightness.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								crates/servicepoint/src/brightness.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,111 @@
 | 
				
			||||||
 | 
					use crate::{Grid, PrimitiveGrid};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(feature = "rand")]
 | 
				
			||||||
 | 
					use rand::{
 | 
				
			||||||
 | 
					    distributions::{Distribution, Standard},
 | 
				
			||||||
 | 
					    Rng,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A display brightness value, checked for correct value range
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Examples
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					/// # use servicepoint::{Brightness, Command, Connection};
 | 
				
			||||||
 | 
					/// let b = Brightness::MAX;
 | 
				
			||||||
 | 
					/// let val: u8 = b.into();
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// let b = Brightness::try_from(7).unwrap();
 | 
				
			||||||
 | 
					/// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
				
			||||||
 | 
					/// let result = connection.send(Command::Brightness(b));
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					#[derive(Debug, Copy, Clone, PartialEq)]
 | 
				
			||||||
 | 
					pub struct Brightness(u8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A grid containing brightness values.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Examples
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```rust
 | 
				
			||||||
 | 
					/// # use servicepoint::{Brightness, BrightnessGrid, Command, Connection, Grid, Origin};
 | 
				
			||||||
 | 
					/// let mut grid = BrightnessGrid::new(2,2);
 | 
				
			||||||
 | 
					/// grid.set(0, 0, Brightness::MIN);
 | 
				
			||||||
 | 
					/// grid.set(1, 1, Brightness::MIN);
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
				
			||||||
 | 
					/// connection.send(Command::CharBrightness(Origin::new(3, 7), grid)).unwrap()
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					pub type BrightnessGrid = PrimitiveGrid<Brightness>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<Brightness> for u8 {
 | 
				
			||||||
 | 
					    fn from(brightness: Brightness) -> Self {
 | 
				
			||||||
 | 
					        brightness.0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl TryFrom<u8> for Brightness {
 | 
				
			||||||
 | 
					    type Error = u8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn try_from(value: u8) -> Result<Self, Self::Error> {
 | 
				
			||||||
 | 
					        if value > Self::MAX.0 {
 | 
				
			||||||
 | 
					            Err(value)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            Ok(Brightness(value))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Brightness {
 | 
				
			||||||
 | 
					    /// highest possible brightness value, 11
 | 
				
			||||||
 | 
					    pub const MAX: Brightness = Brightness(11);
 | 
				
			||||||
 | 
					    /// lowest possible brightness value, 0
 | 
				
			||||||
 | 
					    pub const MIN: Brightness = Brightness(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for Brightness {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self::MAX
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<BrightnessGrid> for Vec<u8> {
 | 
				
			||||||
 | 
					    fn from(value: PrimitiveGrid<Brightness>) -> Self {
 | 
				
			||||||
 | 
					        value
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .map(|brightness| (*brightness).into())
 | 
				
			||||||
 | 
					            .collect()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<BrightnessGrid> for PrimitiveGrid<u8> {
 | 
				
			||||||
 | 
					    fn from(value: PrimitiveGrid<Brightness>) -> Self {
 | 
				
			||||||
 | 
					        let u8s = value
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .map(|brightness| (*brightness).into())
 | 
				
			||||||
 | 
					            .collect::<Vec<u8>>();
 | 
				
			||||||
 | 
					        PrimitiveGrid::load(value.width(), value.height(), &u8s)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl TryFrom<PrimitiveGrid<u8>> for BrightnessGrid {
 | 
				
			||||||
 | 
					    type Error = u8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn try_from(value: PrimitiveGrid<u8>) -> Result<Self, Self::Error> {
 | 
				
			||||||
 | 
					        let brightnesses = value
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .map(|b| Brightness::try_from(*b))
 | 
				
			||||||
 | 
					            .collect::<Result<Vec<Brightness>, _>>()?;
 | 
				
			||||||
 | 
					        Ok(BrightnessGrid::load(
 | 
				
			||||||
 | 
					            value.width(),
 | 
				
			||||||
 | 
					            value.height(),
 | 
				
			||||||
 | 
					            &brightnesses,
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(feature = "rand")]
 | 
				
			||||||
 | 
					impl Distribution<Brightness> for Standard {
 | 
				
			||||||
 | 
					    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Brightness {
 | 
				
			||||||
 | 
					        Brightness(rng.gen_range(Brightness::MIN.0..=Brightness::MAX.0))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,183 +1,168 @@
 | 
				
			||||||
use bitvec::prelude::BitVec;
 | 
					use bitvec::prelude::BitVec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::command_code::CommandCode;
 | 
					 | 
				
			||||||
use crate::compression::{into_compressed, into_decompressed};
 | 
					 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    ByteGrid, CompressionCode, Grid, Header, Packet, PixelGrid, SpBitVec,
 | 
					    command_code::CommandCode, compression::into_decompressed, Brightness,
 | 
				
			||||||
    TILE_SIZE,
 | 
					    BrightnessGrid, CompressionCode, Header, Origin, Packet, PixelGrid, Pixels,
 | 
				
			||||||
 | 
					    PrimitiveGrid, SpBitVec, Tiles, TILE_SIZE,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// An origin marks the top left position of a window sent to the display.
 | 
					 | 
				
			||||||
#[derive(Debug, Clone, Copy, PartialEq)]
 | 
					 | 
				
			||||||
pub struct Origin(pub usize, pub usize);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl std::ops::Add<Origin> for Origin {
 | 
					 | 
				
			||||||
    type Output = Origin;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn add(self, rhs: Origin) -> Self::Output {
 | 
					 | 
				
			||||||
        let Origin(x1, y1) = self;
 | 
					 | 
				
			||||||
        let Origin(x2, y2) = rhs;
 | 
					 | 
				
			||||||
        Origin(x1 + x2, y1 + y2)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Type alias for documenting the meaning of the u16 in enum values
 | 
					/// Type alias for documenting the meaning of the u16 in enum values
 | 
				
			||||||
pub type Offset = usize;
 | 
					pub type Offset = usize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Type alias for documenting the meaning of the u16 in enum values
 | 
					/// A grid containing codepage 437 characters.
 | 
				
			||||||
pub type Brightness = u8;
 | 
					///
 | 
				
			||||||
 | 
					/// The encoding is currently not enforced.
 | 
				
			||||||
 | 
					pub type Cp437Grid = PrimitiveGrid<u8>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A command to send to the display.
 | 
					/// A low-level display command.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// This struct and associated functions implement the UDP protocol for the display.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// To send a `Command`, use a `Connection`.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Examples
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```rust
 | 
				
			||||||
 | 
					/// # use servicepoint::{Brightness, Command, Connection, Packet};
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // create command
 | 
				
			||||||
 | 
					/// let command = Command::Brightness(Brightness::MAX);
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // turn command into Packet
 | 
				
			||||||
 | 
					/// let packet: Packet = command.clone().into();
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // read command from packet
 | 
				
			||||||
 | 
					/// let round_tripped = Command::try_from(packet).unwrap();
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // round tripping produces exact copy
 | 
				
			||||||
 | 
					/// assert_eq!(command, round_tripped);
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // send command
 | 
				
			||||||
 | 
					/// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
				
			||||||
 | 
					/// connection.send(command).unwrap();
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
pub enum Command {
 | 
					pub enum Command {
 | 
				
			||||||
    /// Set all pixels to the off state
 | 
					    /// Set all pixels to the off state. Does not affect brightness.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Examples
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// ```rust
 | 
				
			||||||
 | 
					    /// # use servicepoint::{Command, Connection};
 | 
				
			||||||
 | 
					    /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
				
			||||||
 | 
					    /// connection.send(Command::Clear).unwrap();
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
    Clear,
 | 
					    Clear,
 | 
				
			||||||
    /// Kills the udp daemon, usually results in a reboot of the display.
 | 
					
 | 
				
			||||||
    HardReset,
 | 
					    /// Show text on the screen.
 | 
				
			||||||
    /// Slowly decrease brightness until off? Untested.
 | 
					    ///
 | 
				
			||||||
    FadeOut,
 | 
					    /// <div class="warning">
 | 
				
			||||||
    /// Set the brightness of tiles
 | 
					    ///     The library does not currently convert between UTF-8 and CP-437.
 | 
				
			||||||
    CharBrightness(Origin, ByteGrid),
 | 
					    ///     Because Rust expects UTF-8 strings, it might be necessary to only send ASCII for now.
 | 
				
			||||||
    /// Set the brightness of all tiles
 | 
					    /// </div>
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Examples
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// ```rust
 | 
				
			||||||
 | 
					    /// # use servicepoint::{Command, Connection, Cp437Grid, Origin};
 | 
				
			||||||
 | 
					    /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
				
			||||||
 | 
					    /// let chars = ['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd'].map(move |c| c as u8);
 | 
				
			||||||
 | 
					    /// let grid = Cp437Grid::load(5, 2, &chars);
 | 
				
			||||||
 | 
					    /// connection.send(Command::Cp437Data(Origin::new(2, 2), grid)).unwrap();
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
 | 
					    Cp437Data(Origin<Tiles>, Cp437Grid),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Sets a window of pixels to the specified values
 | 
				
			||||||
 | 
					    BitmapLinearWin(Origin<Pixels>, PixelGrid, CompressionCode),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Set the brightness of all tiles to the same value.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Examples
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// ```rust
 | 
				
			||||||
 | 
					    /// # use servicepoint::{Brightness, Command, Connection};
 | 
				
			||||||
 | 
					    /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
				
			||||||
 | 
					    /// let command = Command::Brightness(Brightness::MAX);
 | 
				
			||||||
 | 
					    /// connection.send(command).unwrap();
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
    Brightness(Brightness),
 | 
					    Brightness(Brightness),
 | 
				
			||||||
    #[deprecated]
 | 
					
 | 
				
			||||||
    /// Legacy command code, gets ignored by the real display.
 | 
					    /// Set the brightness of individual tiles in a rectangular area of the display.
 | 
				
			||||||
    BitmapLegacy,
 | 
					    CharBrightness(Origin<Tiles>, BrightnessGrid),
 | 
				
			||||||
    /// Set pixel data starting at the offset.
 | 
					
 | 
				
			||||||
 | 
					    /// Set pixel data starting at the pixel offset on screen.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The screen will continuously overwrite more pixel data without regarding the offset, meaning
 | 
				
			||||||
 | 
					    /// once the starting row is full, overwriting will continue on column 0.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
    /// The contained `BitVec` is always uncompressed.
 | 
					    /// The contained `BitVec` is always uncompressed.
 | 
				
			||||||
    BitmapLinear(Offset, SpBitVec, CompressionCode),
 | 
					    BitmapLinear(Offset, SpBitVec, CompressionCode),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Set pixel data according to an and-mask starting at the offset.
 | 
					    /// Set pixel data according to an and-mask starting at the offset.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The screen will continuously overwrite more pixel data without regarding the offset, meaning
 | 
				
			||||||
 | 
					    /// once the starting row is full, overwriting will continue on column 0.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
    /// The contained `BitVec` is always uncompressed.
 | 
					    /// The contained `BitVec` is always uncompressed.
 | 
				
			||||||
    BitmapLinearAnd(Offset, SpBitVec, CompressionCode),
 | 
					    BitmapLinearAnd(Offset, SpBitVec, CompressionCode),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Set pixel data according to an or-mask starting at the offset.
 | 
					    /// Set pixel data according to an or-mask starting at the offset.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The screen will continuously overwrite more pixel data without regarding the offset, meaning
 | 
				
			||||||
 | 
					    /// once the starting row is full, overwriting will continue on column 0.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
    /// The contained `BitVec` is always uncompressed.
 | 
					    /// The contained `BitVec` is always uncompressed.
 | 
				
			||||||
    BitmapLinearOr(Offset, SpBitVec, CompressionCode),
 | 
					    BitmapLinearOr(Offset, SpBitVec, CompressionCode),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Set pixel data according to a xor-mask starting at the offset.
 | 
					    /// Set pixel data according to a xor-mask starting at the offset.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The screen will continuously overwrite more pixel data without regarding the offset, meaning
 | 
				
			||||||
 | 
					    /// once the starting row is full, overwriting will continue on column 0.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
    /// The contained `BitVec` is always uncompressed.
 | 
					    /// The contained `BitVec` is always uncompressed.
 | 
				
			||||||
    BitmapLinearXor(Offset, SpBitVec, CompressionCode),
 | 
					    BitmapLinearXor(Offset, SpBitVec, CompressionCode),
 | 
				
			||||||
    /// Show text on the screen. Note that the byte data has to be CP437 encoded.
 | 
					 | 
				
			||||||
    Cp437Data(Origin, ByteGrid),
 | 
					 | 
				
			||||||
    /// Sets a window of pixels to the specified values
 | 
					 | 
				
			||||||
    BitmapLinearWin(Origin, PixelGrid, CompressionCode),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl From<Command> for Packet {
 | 
					    /// Kills the udp daemon on the display, which usually results in a restart.
 | 
				
			||||||
    /// Move the `Command` into a `Packet` instance for sending.
 | 
					    ///
 | 
				
			||||||
    #[allow(clippy::cast_possible_truncation)]
 | 
					    /// Please do not send this in your normal program flow.
 | 
				
			||||||
    fn from(value: Command) -> Self {
 | 
					    ///
 | 
				
			||||||
        match value {
 | 
					    /// # Examples
 | 
				
			||||||
            Command::Clear => Command::command_code_only(CommandCode::Clear),
 | 
					    ///
 | 
				
			||||||
            Command::FadeOut => {
 | 
					    /// ```rust
 | 
				
			||||||
                Command::command_code_only(CommandCode::FadeOut)
 | 
					    /// # use servicepoint::{Command, Connection};
 | 
				
			||||||
            }
 | 
					    /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
				
			||||||
            Command::HardReset => {
 | 
					    /// connection.send(Command::HardReset).unwrap();
 | 
				
			||||||
                Command::command_code_only(CommandCode::HardReset)
 | 
					    /// ```
 | 
				
			||||||
            }
 | 
					    HardReset,
 | 
				
			||||||
            #[allow(deprecated)]
 | 
					 | 
				
			||||||
            Command::BitmapLegacy => {
 | 
					 | 
				
			||||||
                Command::command_code_only(CommandCode::BitmapLegacy)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Command::CharBrightness(Origin(x, y), grid) => Packet(
 | 
					 | 
				
			||||||
                Header(
 | 
					 | 
				
			||||||
                    CommandCode::CharBrightness.into(),
 | 
					 | 
				
			||||||
                    x as u16,
 | 
					 | 
				
			||||||
                    y as u16,
 | 
					 | 
				
			||||||
                    grid.width() as u16,
 | 
					 | 
				
			||||||
                    grid.height() as u16,
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                grid.into(),
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            Command::Brightness(brightness) => Packet(
 | 
					 | 
				
			||||||
                Header(
 | 
					 | 
				
			||||||
                    CommandCode::Brightness.into(),
 | 
					 | 
				
			||||||
                    0x00000,
 | 
					 | 
				
			||||||
                    0x0000,
 | 
					 | 
				
			||||||
                    0x0000,
 | 
					 | 
				
			||||||
                    0x0000,
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                vec![brightness],
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            Command::BitmapLinearWin(origin, pixels, compression) => {
 | 
					 | 
				
			||||||
                bitmap_win_into_packet(origin, pixels, compression)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Command::BitmapLinear(offset, bits, compression) => {
 | 
					 | 
				
			||||||
                Command::bitmap_linear_into_packet(
 | 
					 | 
				
			||||||
                    CommandCode::BitmapLinear,
 | 
					 | 
				
			||||||
                    offset,
 | 
					 | 
				
			||||||
                    compression,
 | 
					 | 
				
			||||||
                    bits.into(),
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Command::BitmapLinearAnd(offset, bits, compression) => {
 | 
					 | 
				
			||||||
                Command::bitmap_linear_into_packet(
 | 
					 | 
				
			||||||
                    CommandCode::BitmapLinearAnd,
 | 
					 | 
				
			||||||
                    offset,
 | 
					 | 
				
			||||||
                    compression,
 | 
					 | 
				
			||||||
                    bits.into(),
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Command::BitmapLinearOr(offset, bits, compression) => {
 | 
					 | 
				
			||||||
                Command::bitmap_linear_into_packet(
 | 
					 | 
				
			||||||
                    CommandCode::BitmapLinearOr,
 | 
					 | 
				
			||||||
                    offset,
 | 
					 | 
				
			||||||
                    compression,
 | 
					 | 
				
			||||||
                    bits.into(),
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Command::BitmapLinearXor(offset, bits, compression) => {
 | 
					 | 
				
			||||||
                Command::bitmap_linear_into_packet(
 | 
					 | 
				
			||||||
                    CommandCode::BitmapLinearXor,
 | 
					 | 
				
			||||||
                    offset,
 | 
					 | 
				
			||||||
                    compression,
 | 
					 | 
				
			||||||
                    bits.into(),
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Command::Cp437Data(Origin(x, y), grid) => Packet(
 | 
					 | 
				
			||||||
                Header(
 | 
					 | 
				
			||||||
                    CommandCode::Cp437Data.into(),
 | 
					 | 
				
			||||||
                    x as u16,
 | 
					 | 
				
			||||||
                    y as u16,
 | 
					 | 
				
			||||||
                    grid.width() as u16,
 | 
					 | 
				
			||||||
                    grid.height() as u16,
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                grid.into(),
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[allow(clippy::cast_possible_truncation)]
 | 
					    /// <div class="warning">Untested</div>
 | 
				
			||||||
fn bitmap_win_into_packet(
 | 
					    ///
 | 
				
			||||||
    origin: Origin,
 | 
					    /// Slowly decrease brightness until off or something like that?
 | 
				
			||||||
    pixels: PixelGrid,
 | 
					    ///
 | 
				
			||||||
    compression: CompressionCode,
 | 
					    /// # Examples
 | 
				
			||||||
) -> Packet {
 | 
					    ///
 | 
				
			||||||
    let Origin(pixel_x, pixel_y) = origin;
 | 
					    /// ```rust
 | 
				
			||||||
    debug_assert_eq!(pixel_x % 8, 0);
 | 
					    /// # use servicepoint::{Command, Connection};
 | 
				
			||||||
    debug_assert_eq!(pixels.width() % 8, 0);
 | 
					    /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
				
			||||||
 | 
					    /// connection.send(Command::FadeOut).unwrap();
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
 | 
					    FadeOut,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let tile_x = (pixel_x / TILE_SIZE) as u16;
 | 
					    /// Legacy command code, gets ignored by the real display.
 | 
				
			||||||
    let tile_w = (pixels.width() / TILE_SIZE) as u16;
 | 
					    ///
 | 
				
			||||||
    let pixel_h = pixels.height() as u16;
 | 
					    /// Might be useful as a noop package.
 | 
				
			||||||
    let payload = into_compressed(compression, pixels.into());
 | 
					    ///
 | 
				
			||||||
    let command = match compression {
 | 
					    /// # Examples
 | 
				
			||||||
        CompressionCode::Uncompressed => {
 | 
					    ///
 | 
				
			||||||
            CommandCode::BitmapLinearWinUncompressed
 | 
					    /// ```rust
 | 
				
			||||||
        }
 | 
					    /// # use servicepoint::{Command, Connection};
 | 
				
			||||||
        #[cfg(feature = "compression_zlib")]
 | 
					    /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
				
			||||||
        CompressionCode::Zlib => CommandCode::BitmapLinearWinZlib,
 | 
					    /// // this sends a packet that does nothing
 | 
				
			||||||
        #[cfg(feature = "compression_bzip2")]
 | 
					    /// # #[allow(deprecated)]
 | 
				
			||||||
        CompressionCode::Bzip2 => CommandCode::BitmapLinearWinBzip2,
 | 
					    /// connection.send(Command::BitmapLegacy).unwrap();
 | 
				
			||||||
        #[cfg(feature = "compression_lzma")]
 | 
					    /// ```
 | 
				
			||||||
        CompressionCode::Lzma => CommandCode::BitmapLinearWinLzma,
 | 
					    #[deprecated]
 | 
				
			||||||
        #[cfg(feature = "compression_zstd")]
 | 
					    BitmapLegacy,
 | 
				
			||||||
        CompressionCode::Zstd => CommandCode::BitmapLinearWinZstd,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Packet(
 | 
					 | 
				
			||||||
        Header(command.into(), tile_x, pixel_y as u16, tile_w, pixel_h),
 | 
					 | 
				
			||||||
        payload,
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
| 
						 | 
					@ -196,6 +181,8 @@ pub enum TryFromPacketError {
 | 
				
			||||||
    InvalidCompressionCode(u16),
 | 
					    InvalidCompressionCode(u16),
 | 
				
			||||||
    /// Decompression of the payload failed. This can be caused by corrupted packets.
 | 
					    /// Decompression of the payload failed. This can be caused by corrupted packets.
 | 
				
			||||||
    DecompressionFailed,
 | 
					    DecompressionFailed,
 | 
				
			||||||
 | 
					    /// The given brightness value is out of bounds
 | 
				
			||||||
 | 
					    InvalidBrightness(u8),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl TryFrom<Packet> for Command {
 | 
					impl TryFrom<Packet> for Command {
 | 
				
			||||||
| 
						 | 
					@ -203,7 +190,7 @@ impl TryFrom<Packet> for Command {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Try to interpret the `Packet` as one containing a `Command`
 | 
					    /// Try to interpret the `Packet` as one containing a `Command`
 | 
				
			||||||
    fn try_from(packet: Packet) -> Result<Self, Self::Error> {
 | 
					    fn try_from(packet: Packet) -> Result<Self, Self::Error> {
 | 
				
			||||||
        let Packet(Header(command_u16, a, b, c, d), _) = packet;
 | 
					        let Packet(Header(command_u16, a, _, _, _), _) = packet;
 | 
				
			||||||
        let command_code = match CommandCode::try_from(command_u16) {
 | 
					        let command_code = match CommandCode::try_from(command_u16) {
 | 
				
			||||||
            Err(()) => {
 | 
					            Err(()) => {
 | 
				
			||||||
                return Err(TryFromPacketError::InvalidCommand(command_u16));
 | 
					                return Err(TryFromPacketError::InvalidCommand(command_u16));
 | 
				
			||||||
| 
						 | 
					@ -212,47 +199,19 @@ impl TryFrom<Packet> for Command {
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        match command_code {
 | 
					        match command_code {
 | 
				
			||||||
            CommandCode::Clear => match Self::check_command_only(packet) {
 | 
					            CommandCode::Clear => {
 | 
				
			||||||
                Some(err) => Err(err),
 | 
					                Self::packet_into_command_only(packet, Command::Clear)
 | 
				
			||||||
                None => Ok(Command::Clear),
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            CommandCode::Brightness => {
 | 
					 | 
				
			||||||
                let Packet(header, payload) = packet;
 | 
					 | 
				
			||||||
                if payload.len() != 1 {
 | 
					 | 
				
			||||||
                    return Err(TryFromPacketError::UnexpectedPayloadSize(
 | 
					 | 
				
			||||||
                        1,
 | 
					 | 
				
			||||||
                        payload.len(),
 | 
					 | 
				
			||||||
                    ));
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            CommandCode::Brightness => Self::packet_into_brightness(&packet),
 | 
				
			||||||
                let Header(_, a, b, c, d) = header;
 | 
					            CommandCode::HardReset => {
 | 
				
			||||||
                if a != 0 || b != 0 || c != 0 || d != 0 {
 | 
					                Self::packet_into_command_only(packet, Command::HardReset)
 | 
				
			||||||
                    Err(TryFromPacketError::ExtraneousHeaderValues)
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    Ok(Command::Brightness(payload[0]))
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            CommandCode::FadeOut => {
 | 
				
			||||||
 | 
					                Self::packet_into_command_only(packet, Command::FadeOut)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            CommandCode::HardReset => match Self::check_command_only(packet) {
 | 
					            CommandCode::Cp437Data => Self::packet_into_cp437(&packet),
 | 
				
			||||||
                Some(err) => Err(err),
 | 
					 | 
				
			||||||
                None => Ok(Command::HardReset),
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            CommandCode::FadeOut => match Self::check_command_only(packet) {
 | 
					 | 
				
			||||||
                Some(err) => Err(err),
 | 
					 | 
				
			||||||
                None => Ok(Command::FadeOut),
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            CommandCode::Cp437Data => {
 | 
					 | 
				
			||||||
                let Packet(_, payload) = packet;
 | 
					 | 
				
			||||||
                Ok(Command::Cp437Data(
 | 
					 | 
				
			||||||
                    Origin(a as usize, b as usize),
 | 
					 | 
				
			||||||
                    ByteGrid::load(c as usize, d as usize, &payload),
 | 
					 | 
				
			||||||
                ))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            CommandCode::CharBrightness => {
 | 
					            CommandCode::CharBrightness => {
 | 
				
			||||||
                let Packet(_, payload) = packet;
 | 
					                Self::packet_into_char_brightness(&packet)
 | 
				
			||||||
                Ok(Command::CharBrightness(
 | 
					 | 
				
			||||||
                    Origin(a as usize, b as usize),
 | 
					 | 
				
			||||||
                    ByteGrid::load(c as usize, d as usize, &payload),
 | 
					 | 
				
			||||||
                ))
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            #[allow(deprecated)]
 | 
					            #[allow(deprecated)]
 | 
				
			||||||
            CommandCode::BitmapLegacy => Ok(Command::BitmapLegacy),
 | 
					            CommandCode::BitmapLegacy => Ok(Command::BitmapLegacy),
 | 
				
			||||||
| 
						 | 
					@ -316,7 +275,7 @@ impl Command {
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(Command::BitmapLinearWin(
 | 
					        Ok(Command::BitmapLinearWin(
 | 
				
			||||||
            Origin(tiles_x as usize * TILE_SIZE, pixels_y as usize),
 | 
					            Origin::new(tiles_x as usize * TILE_SIZE, pixels_y as usize),
 | 
				
			||||||
            PixelGrid::load(
 | 
					            PixelGrid::load(
 | 
				
			||||||
                tile_w as usize * TILE_SIZE,
 | 
					                tile_w as usize * TILE_SIZE,
 | 
				
			||||||
                pixel_h as usize,
 | 
					                pixel_h as usize,
 | 
				
			||||||
| 
						 | 
					@ -326,42 +285,18 @@ impl Command {
 | 
				
			||||||
        ))
 | 
					        ))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Helper method for `BitMapLinear*`-Commands into `Packet`
 | 
					 | 
				
			||||||
    #[allow(clippy::cast_possible_truncation)]
 | 
					 | 
				
			||||||
    fn bitmap_linear_into_packet(
 | 
					 | 
				
			||||||
        command: CommandCode,
 | 
					 | 
				
			||||||
        offset: Offset,
 | 
					 | 
				
			||||||
        compression: CompressionCode,
 | 
					 | 
				
			||||||
        payload: Vec<u8>,
 | 
					 | 
				
			||||||
    ) -> Packet {
 | 
					 | 
				
			||||||
        let length = payload.len() as u16;
 | 
					 | 
				
			||||||
        let payload = into_compressed(compression, payload);
 | 
					 | 
				
			||||||
        Packet(
 | 
					 | 
				
			||||||
            Header(
 | 
					 | 
				
			||||||
                command.into(),
 | 
					 | 
				
			||||||
                offset as u16,
 | 
					 | 
				
			||||||
                length,
 | 
					 | 
				
			||||||
                compression.into(),
 | 
					 | 
				
			||||||
                0,
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            payload,
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Helper method for creating empty packets only containing the command code
 | 
					 | 
				
			||||||
    fn command_code_only(code: CommandCode) -> Packet {
 | 
					 | 
				
			||||||
        Packet(Header(code.into(), 0x0000, 0x0000, 0x0000, 0x0000), vec![])
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Helper method for checking that a packet is empty and only contains a command code
 | 
					    /// Helper method for checking that a packet is empty and only contains a command code
 | 
				
			||||||
    fn check_command_only(packet: Packet) -> Option<TryFromPacketError> {
 | 
					    fn packet_into_command_only(
 | 
				
			||||||
 | 
					        packet: Packet,
 | 
				
			||||||
 | 
					        command: Command,
 | 
				
			||||||
 | 
					    ) -> Result<Command, TryFromPacketError> {
 | 
				
			||||||
        let Packet(Header(_, a, b, c, d), payload) = packet;
 | 
					        let Packet(Header(_, a, b, c, d), payload) = packet;
 | 
				
			||||||
        if !payload.is_empty() {
 | 
					        if !payload.is_empty() {
 | 
				
			||||||
            Some(TryFromPacketError::UnexpectedPayloadSize(0, payload.len()))
 | 
					            Err(TryFromPacketError::UnexpectedPayloadSize(0, payload.len()))
 | 
				
			||||||
        } else if a != 0 || b != 0 || c != 0 || d != 0 {
 | 
					        } else if a != 0 || b != 0 || c != 0 || d != 0 {
 | 
				
			||||||
            Some(TryFromPacketError::ExtraneousHeaderValues)
 | 
					            Err(TryFromPacketError::ExtraneousHeaderValues)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            None
 | 
					            Ok(command)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -391,16 +326,63 @@ impl Command {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok((BitVec::from_vec(payload), sub))
 | 
					        Ok((BitVec::from_vec(payload), sub))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn packet_into_char_brightness(
 | 
				
			||||||
 | 
					        packet: &Packet,
 | 
				
			||||||
 | 
					    ) -> Result<Command, TryFromPacketError> {
 | 
				
			||||||
 | 
					        let Packet(Header(_, x, y, width, height), payload) = packet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let grid =
 | 
				
			||||||
 | 
					            PrimitiveGrid::load(*width as usize, *height as usize, payload);
 | 
				
			||||||
 | 
					        let grid = match BrightnessGrid::try_from(grid) {
 | 
				
			||||||
 | 
					            Ok(grid) => grid,
 | 
				
			||||||
 | 
					            Err(val) => return Err(TryFromPacketError::InvalidBrightness(val)),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(Command::CharBrightness(
 | 
				
			||||||
 | 
					            Origin::new(*x as usize, *y as usize),
 | 
				
			||||||
 | 
					            grid,
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn packet_into_brightness(
 | 
				
			||||||
 | 
					        packet: &Packet,
 | 
				
			||||||
 | 
					    ) -> Result<Command, TryFromPacketError> {
 | 
				
			||||||
 | 
					        let Packet(Header(_, a, b, c, d), payload) = packet;
 | 
				
			||||||
 | 
					        if payload.len() != 1 {
 | 
				
			||||||
 | 
					            return Err(TryFromPacketError::UnexpectedPayloadSize(
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                payload.len(),
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if *a != 0 || *b != 0 || *c != 0 || *d != 0 {
 | 
				
			||||||
 | 
					            return Err(TryFromPacketError::ExtraneousHeaderValues);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        match Brightness::try_from(payload[0]) {
 | 
				
			||||||
 | 
					            Ok(b) => Ok(Command::Brightness(b)),
 | 
				
			||||||
 | 
					            Err(_) => Err(TryFromPacketError::InvalidBrightness(payload[0])),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn packet_into_cp437(
 | 
				
			||||||
 | 
					        packet: &Packet,
 | 
				
			||||||
 | 
					    ) -> Result<Command, TryFromPacketError> {
 | 
				
			||||||
 | 
					        let Packet(Header(_, a, b, c, d), payload) = packet;
 | 
				
			||||||
 | 
					        Ok(Command::Cp437Data(
 | 
				
			||||||
 | 
					            Origin::new(*a as usize, *b as usize),
 | 
				
			||||||
 | 
					            Cp437Grid::load(*c as usize, *d as usize, payload),
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use bitvec::prelude::BitVec;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    use crate::command::TryFromPacketError;
 | 
					 | 
				
			||||||
    use crate::command_code::CommandCode;
 | 
					 | 
				
			||||||
    use crate::{
 | 
					    use crate::{
 | 
				
			||||||
        ByteGrid, Command, CompressionCode, Header, Origin, Packet, PixelGrid,
 | 
					        bitvec::prelude::BitVec, command::TryFromPacketError,
 | 
				
			||||||
 | 
					        command_code::CommandCode, origin::Pixels, Brightness, Command,
 | 
				
			||||||
 | 
					        CompressionCode, Header, Origin, Packet, PixelGrid, PrimitiveGrid,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn round_trip(original: Command) {
 | 
					    fn round_trip(original: Command) {
 | 
				
			||||||
| 
						 | 
					@ -443,7 +425,7 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn round_trip_brightness() {
 | 
					    fn round_trip_brightness() {
 | 
				
			||||||
        round_trip(Command::Brightness(6));
 | 
					        round_trip(Command::Brightness(Brightness::try_from(6).unwrap()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
| 
						 | 
					@ -454,12 +436,18 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn round_trip_char_brightness() {
 | 
					    fn round_trip_char_brightness() {
 | 
				
			||||||
        round_trip(Command::CharBrightness(Origin(5, 2), ByteGrid::new(7, 5)));
 | 
					        round_trip(Command::CharBrightness(
 | 
				
			||||||
 | 
					            Origin::new(5, 2),
 | 
				
			||||||
 | 
					            PrimitiveGrid::new(7, 5),
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn round_trip_cp437_data() {
 | 
					    fn round_trip_cp437_data() {
 | 
				
			||||||
        round_trip(Command::Cp437Data(Origin(5, 2), ByteGrid::new(7, 5)));
 | 
					        round_trip(Command::Cp437Data(
 | 
				
			||||||
 | 
					            Origin::new(5, 2),
 | 
				
			||||||
 | 
					            PrimitiveGrid::new(7, 5),
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
| 
						 | 
					@ -486,7 +474,7 @@ mod tests {
 | 
				
			||||||
                compression,
 | 
					                compression,
 | 
				
			||||||
            ));
 | 
					            ));
 | 
				
			||||||
            round_trip(Command::BitmapLinearWin(
 | 
					            round_trip(Command::BitmapLinearWin(
 | 
				
			||||||
                Origin(0, 0),
 | 
					                Origin::new(0, 0),
 | 
				
			||||||
                PixelGrid::max_sized(),
 | 
					                PixelGrid::max_sized(),
 | 
				
			||||||
                compression,
 | 
					                compression,
 | 
				
			||||||
            ));
 | 
					            ));
 | 
				
			||||||
| 
						 | 
					@ -572,7 +560,7 @@ mod tests {
 | 
				
			||||||
    fn error_decompression_failed_win() {
 | 
					    fn error_decompression_failed_win() {
 | 
				
			||||||
        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(16, 8),
 | 
					                Origin::new(16, 8),
 | 
				
			||||||
                PixelGrid::new(8, 8),
 | 
					                PixelGrid::new(8, 8),
 | 
				
			||||||
                compression,
 | 
					                compression,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
| 
						 | 
					@ -696,6 +684,9 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn origin_add() {
 | 
					    fn origin_add() {
 | 
				
			||||||
        assert_eq!(Origin(4, 2), Origin(1, 0) + Origin(3, 2));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            Origin::<Pixels>::new(4, 2),
 | 
				
			||||||
 | 
					            Origin::new(1, 0) + Origin::new(3, 2)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,17 @@
 | 
				
			||||||
/// Specifies the kind of compression to use. Availability depends on features.
 | 
					/// Specifies the kind of compression to use. Availability depends on features.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Examples
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```rust
 | 
				
			||||||
 | 
					/// # use servicepoint::{Command, CompressionCode, Origin, PixelGrid};
 | 
				
			||||||
 | 
					/// // create command without payload compression
 | 
				
			||||||
 | 
					/// # let pixels = PixelGrid::max_sized();
 | 
				
			||||||
 | 
					/// _ = Command::BitmapLinearWin(Origin::new(0, 0), pixels, CompressionCode::Uncompressed);
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // create command with payload compressed with lzma and appropriate header flags
 | 
				
			||||||
 | 
					/// # let pixels = PixelGrid::max_sized();
 | 
				
			||||||
 | 
					/// _ = Command::BitmapLinearWin(Origin::new(0, 0), pixels, CompressionCode::Lzma);
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
#[repr(u16)]
 | 
					#[repr(u16)]
 | 
				
			||||||
#[derive(Debug, Clone, Copy, PartialEq)]
 | 
					#[derive(Debug, Clone, Copy, PartialEq)]
 | 
				
			||||||
pub enum CompressionCode {
 | 
					pub enum CompressionCode {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,15 @@ use log::{debug, info};
 | 
				
			||||||
use crate::Packet;
 | 
					use crate::Packet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A connection to the display.
 | 
					/// A connection to the display.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Examples
 | 
				
			||||||
 | 
					/// ```rust
 | 
				
			||||||
 | 
					/// # use servicepoint::Command;
 | 
				
			||||||
 | 
					/// let connection = servicepoint::Connection::open("172.23.42.29:2342")
 | 
				
			||||||
 | 
					///     .expect("connection failed");
 | 
				
			||||||
 | 
					///  connection.send(Command::Clear)
 | 
				
			||||||
 | 
					///     .expect("send failed");
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
pub struct Connection {
 | 
					pub struct Connection {
 | 
				
			||||||
    socket: UdpSocket,
 | 
					    socket: UdpSocket,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -46,21 +55,12 @@ impl Connection {
 | 
				
			||||||
    /// # Examples
 | 
					    /// # Examples
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// ```rust
 | 
					    /// ```rust
 | 
				
			||||||
    /// use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
 | 
					    /// # use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
 | 
				
			||||||
    /// 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");
 | 
				
			||||||
    ///
 | 
					    ///  // turn off all pixels on display
 | 
				
			||||||
    ///  // turn off all pixels
 | 
					 | 
				
			||||||
    ///  connection.send(Command::Clear)
 | 
					    ///  connection.send(Command::Clear)
 | 
				
			||||||
    ///     .expect("send failed");
 | 
					    ///     .expect("send failed");
 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    ///  // turn on all pixels
 | 
					 | 
				
			||||||
    ///  let mut pixels = PixelGrid::max_sized();
 | 
					 | 
				
			||||||
    ///  pixels.fill(true);
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    ///  // send pixels to display
 | 
					 | 
				
			||||||
    ///  connection.send(Command::BitmapLinearWin(servicepoint::Origin(0, 0), pixels, CompressionCode::Uncompressed))
 | 
					 | 
				
			||||||
    ///     .expect("send failed");
 | 
					 | 
				
			||||||
    /// ```
 | 
					    /// ```
 | 
				
			||||||
    pub fn send(
 | 
					    pub fn send(
 | 
				
			||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,13 @@
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// The expectation is that you can create an equal instance with this data given the additional
 | 
					/// The expectation is that you can create an equal instance with this data given the additional
 | 
				
			||||||
/// metadata needed.
 | 
					/// metadata needed.
 | 
				
			||||||
pub trait DataRef {
 | 
					pub trait DataRef<T> {
 | 
				
			||||||
    /// Get the underlying bytes writable.
 | 
					    /// Get the underlying bytes writable.
 | 
				
			||||||
    fn data_ref_mut(&mut self) -> &mut [u8];
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Note that depending on the struct this is implemented on, writing invalid values here might
 | 
				
			||||||
 | 
					    /// lead to panics later in the lifetime of the program or on the receiving side.
 | 
				
			||||||
 | 
					    fn data_ref_mut(&mut self) -> &mut [T];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Get the underlying bytes read-only.
 | 
					    /// Get the underlying bytes read-only.
 | 
				
			||||||
    fn data_ref(&self) -> &[u8];
 | 
					    fn data_ref(&self) -> &[T];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,22 +1,55 @@
 | 
				
			||||||
//! Abstractions for the UDP protocol of the CCCB servicepoint display.
 | 
					//! Abstractions for the UDP protocol of the CCCB servicepoint display.
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! # Examples
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! ```rust
 | 
				
			||||||
 | 
					//! use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! let connection = servicepoint::Connection::open("127.0.0.1:2342")
 | 
				
			||||||
 | 
					//!     .expect("connection failed");
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//!  // turn off all pixels on display
 | 
				
			||||||
 | 
					//!  connection.send(Command::Clear)
 | 
				
			||||||
 | 
					//!     .expect("send failed");
 | 
				
			||||||
 | 
					//! ```
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! ```rust
 | 
				
			||||||
 | 
					//! # use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
 | 
				
			||||||
 | 
					//! # let connection = servicepoint::Connection::open("127.0.0.1:2342").expect("connection failed");
 | 
				
			||||||
 | 
					//!  // turn on all pixels in a grid
 | 
				
			||||||
 | 
					//!  let mut pixels = PixelGrid::max_sized();
 | 
				
			||||||
 | 
					//!  pixels.fill(true);
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//!  // create command to send pixels
 | 
				
			||||||
 | 
					//!  let command = Command::BitmapLinearWin(
 | 
				
			||||||
 | 
					//!     servicepoint::Origin::new(0, 0),
 | 
				
			||||||
 | 
					//!     pixels,
 | 
				
			||||||
 | 
					//!     CompressionCode::Uncompressed
 | 
				
			||||||
 | 
					//!  );
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//!  // send command to display
 | 
				
			||||||
 | 
					//!  connection.send(command).expect("send failed");
 | 
				
			||||||
 | 
					//! ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::time::Duration;
 | 
					use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use bitvec;
 | 
					pub use bitvec;
 | 
				
			||||||
use bitvec::prelude::{BitVec, Msb0};
 | 
					use bitvec::prelude::{BitVec, Msb0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use crate::byte_grid::ByteGrid;
 | 
					pub use crate::brightness::{Brightness, BrightnessGrid};
 | 
				
			||||||
pub use crate::command::{Brightness, Command, Offset, Origin};
 | 
					pub use crate::command::{Command, Cp437Grid, Offset};
 | 
				
			||||||
pub use crate::compression_code::CompressionCode;
 | 
					pub use crate::compression_code::CompressionCode;
 | 
				
			||||||
pub use crate::connection::Connection;
 | 
					pub use crate::connection::Connection;
 | 
				
			||||||
pub use crate::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::packet::{Header, Packet, Payload};
 | 
					pub use crate::packet::{Header, Packet, Payload};
 | 
				
			||||||
pub use crate::pixel_grid::PixelGrid;
 | 
					pub use crate::pixel_grid::PixelGrid;
 | 
				
			||||||
 | 
					pub use crate::primitive_grid::PrimitiveGrid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SpBitVec = BitVec<u8, Msb0>;
 | 
					type SpBitVec = BitVec<u8, Msb0>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod byte_grid;
 | 
					mod brightness;
 | 
				
			||||||
mod command;
 | 
					mod command;
 | 
				
			||||||
mod command_code;
 | 
					mod command_code;
 | 
				
			||||||
mod compression;
 | 
					mod compression;
 | 
				
			||||||
| 
						 | 
					@ -24,28 +57,84 @@ mod compression_code;
 | 
				
			||||||
mod connection;
 | 
					mod connection;
 | 
				
			||||||
mod data_ref;
 | 
					mod data_ref;
 | 
				
			||||||
mod grid;
 | 
					mod grid;
 | 
				
			||||||
 | 
					mod origin;
 | 
				
			||||||
mod packet;
 | 
					mod packet;
 | 
				
			||||||
mod pixel_grid;
 | 
					mod pixel_grid;
 | 
				
			||||||
 | 
					mod primitive_grid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// size of a single tile in one dimension
 | 
					/// size of a single tile in one dimension
 | 
				
			||||||
pub const TILE_SIZE: usize = 8;
 | 
					pub const TILE_SIZE: usize = 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// tile count in the x-direction
 | 
					/// Display tile count in the x-direction
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Examples
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```rust
 | 
				
			||||||
 | 
					/// # use servicepoint::{Cp437Grid, TILE_HEIGHT, TILE_WIDTH};
 | 
				
			||||||
 | 
					/// let grid = Cp437Grid::new(TILE_WIDTH, TILE_HEIGHT);
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
pub const TILE_WIDTH: usize = 56;
 | 
					pub const TILE_WIDTH: usize = 56;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// tile count in the y-direction
 | 
					/// Display tile count in the y-direction
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Examples
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```rust
 | 
				
			||||||
 | 
					/// # use servicepoint::{Cp437Grid, TILE_HEIGHT, TILE_WIDTH};
 | 
				
			||||||
 | 
					/// let grid = Cp437Grid::new(TILE_WIDTH, TILE_HEIGHT);
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
pub const TILE_HEIGHT: usize = 20;
 | 
					pub const TILE_HEIGHT: usize = 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// screen width in pixels
 | 
					/// Display width in pixels
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Examples
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```rust
 | 
				
			||||||
 | 
					/// # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid};
 | 
				
			||||||
 | 
					/// let grid = PixelGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT);
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
pub const PIXEL_WIDTH: usize = TILE_WIDTH * TILE_SIZE;
 | 
					pub const PIXEL_WIDTH: usize = TILE_WIDTH * TILE_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// screen height in pixels
 | 
					/// Display height in pixels
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Examples
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```rust
 | 
				
			||||||
 | 
					/// # use servicepoint::{PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid};
 | 
				
			||||||
 | 
					/// let grid = PixelGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT);
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
pub const PIXEL_HEIGHT: usize = TILE_HEIGHT * TILE_SIZE;
 | 
					pub const PIXEL_HEIGHT: usize = TILE_HEIGHT * TILE_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// pixel count on whole screen
 | 
					/// pixel count on whole screen
 | 
				
			||||||
pub const PIXEL_COUNT: usize = PIXEL_WIDTH * PIXEL_HEIGHT;
 | 
					pub const PIXEL_COUNT: usize = PIXEL_WIDTH * PIXEL_HEIGHT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets.
 | 
					/// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Examples
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```rust
 | 
				
			||||||
 | 
					/// # use std::time::Instant;
 | 
				
			||||||
 | 
					/// # use servicepoint::{Command, CompressionCode, FRAME_PACING, Origin, PixelGrid};
 | 
				
			||||||
 | 
					/// # let connection = servicepoint::Connection::open("172.23.42.29:2342")
 | 
				
			||||||
 | 
					/// #     .expect("connection failed");
 | 
				
			||||||
 | 
					/// # let pixels = PixelGrid::max_sized();
 | 
				
			||||||
 | 
					/// loop {
 | 
				
			||||||
 | 
					///    let start = Instant::now();
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					///    // Change pixels here
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					///    connection.send(Command::BitmapLinearWin(
 | 
				
			||||||
 | 
					///            Origin::new(0,0),
 | 
				
			||||||
 | 
					///            pixels,
 | 
				
			||||||
 | 
					///            CompressionCode::Lzma
 | 
				
			||||||
 | 
					///        ))
 | 
				
			||||||
 | 
					///        .expect("send failed");
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					///    // warning: will crash if resulting duration is negative, e.g. when resuming from standby
 | 
				
			||||||
 | 
					///    std::thread::sleep(FRAME_PACING - start.elapsed());
 | 
				
			||||||
 | 
					///    # break; // prevent doctest from hanging
 | 
				
			||||||
 | 
					/// }
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
pub const FRAME_PACING: Duration = Duration::from_millis(30);
 | 
					pub const FRAME_PACING: Duration = Duration::from_millis(30);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// include README.md in doctest
 | 
					// include README.md in doctest
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										48
									
								
								crates/servicepoint/src/origin.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								crates/servicepoint/src/origin.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,48 @@
 | 
				
			||||||
 | 
					use std::marker::PhantomData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// An origin marks the top left position of a window sent to the display.
 | 
				
			||||||
 | 
					#[derive(Debug, Copy, Clone, PartialEq)]
 | 
				
			||||||
 | 
					pub struct Origin<Unit: DisplayUnit> {
 | 
				
			||||||
 | 
					    /// position in the width direction
 | 
				
			||||||
 | 
					    pub x: usize,
 | 
				
			||||||
 | 
					    /// position in the height direction
 | 
				
			||||||
 | 
					    pub y: usize,
 | 
				
			||||||
 | 
					    phantom_data: PhantomData<Unit>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<Unit: DisplayUnit> Origin<Unit> {
 | 
				
			||||||
 | 
					    /// Create a new `Origin` instance for the provided position.
 | 
				
			||||||
 | 
					    pub fn new(x: usize, y: usize) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            x,
 | 
				
			||||||
 | 
					            y,
 | 
				
			||||||
 | 
					            phantom_data: PhantomData,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: DisplayUnit> std::ops::Add<Origin<T>> for Origin<T> {
 | 
				
			||||||
 | 
					    type Output = Origin<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn add(self, rhs: Origin<T>) -> Self::Output {
 | 
				
			||||||
 | 
					        Origin {
 | 
				
			||||||
 | 
					            x: self.x + rhs.x,
 | 
				
			||||||
 | 
					            y: self.y + rhs.y,
 | 
				
			||||||
 | 
					            phantom_data: PhantomData,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait DisplayUnit {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Marks something to be measured in number of pixels.
 | 
				
			||||||
 | 
					#[derive(Debug, Copy, Clone, PartialEq)]
 | 
				
			||||||
 | 
					pub struct Pixels();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Marks something to be measured in number of iles.
 | 
				
			||||||
 | 
					#[derive(Debug, Copy, Clone, PartialEq)]
 | 
				
			||||||
 | 
					pub struct Tiles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl DisplayUnit for Pixels {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl DisplayUnit for Tiles {}
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,12 @@
 | 
				
			||||||
use std::mem::size_of;
 | 
					use std::mem::size_of;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::command_code::CommandCode;
 | 
				
			||||||
 | 
					use crate::compression::into_compressed;
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    Command, CompressionCode, Grid, Offset, Origin, PixelGrid, Pixels,
 | 
				
			||||||
 | 
					    TILE_SIZE,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A raw header. Should probably not be used directly.
 | 
					/// A raw header. Should probably not be used directly.
 | 
				
			||||||
#[derive(Debug, PartialEq)]
 | 
					#[derive(Debug, PartialEq)]
 | 
				
			||||||
pub struct Header(pub u16, pub u16, pub u16, pub u16, pub u16);
 | 
					pub struct Header(pub u16, pub u16, pub u16, pub u16, pub u16);
 | 
				
			||||||
| 
						 | 
					@ -58,6 +65,151 @@ impl TryFrom<&[u8]> for Packet {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<Command> for Packet {
 | 
				
			||||||
 | 
					    /// Move the `Command` into a `Packet` instance for sending.
 | 
				
			||||||
 | 
					    #[allow(clippy::cast_possible_truncation)]
 | 
				
			||||||
 | 
					    fn from(value: Command) -> Self {
 | 
				
			||||||
 | 
					        match value {
 | 
				
			||||||
 | 
					            Command::Clear => Self::command_code_only(CommandCode::Clear),
 | 
				
			||||||
 | 
					            Command::FadeOut => Self::command_code_only(CommandCode::FadeOut),
 | 
				
			||||||
 | 
					            Command::HardReset => {
 | 
				
			||||||
 | 
					                Self::command_code_only(CommandCode::HardReset)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            #[allow(deprecated)]
 | 
				
			||||||
 | 
					            Command::BitmapLegacy => {
 | 
				
			||||||
 | 
					                Self::command_code_only(CommandCode::BitmapLegacy)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Command::CharBrightness(origin, grid) => Packet(
 | 
				
			||||||
 | 
					                Header(
 | 
				
			||||||
 | 
					                    CommandCode::CharBrightness.into(),
 | 
				
			||||||
 | 
					                    origin.x as u16,
 | 
				
			||||||
 | 
					                    origin.y as u16,
 | 
				
			||||||
 | 
					                    grid.width() as u16,
 | 
				
			||||||
 | 
					                    grid.height() as u16,
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                grid.into(),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            Command::Brightness(brightness) => Packet(
 | 
				
			||||||
 | 
					                Header(
 | 
				
			||||||
 | 
					                    CommandCode::Brightness.into(),
 | 
				
			||||||
 | 
					                    0x00000,
 | 
				
			||||||
 | 
					                    0x0000,
 | 
				
			||||||
 | 
					                    0x0000,
 | 
				
			||||||
 | 
					                    0x0000,
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                vec![brightness.into()],
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            Command::BitmapLinearWin(origin, pixels, compression) => {
 | 
				
			||||||
 | 
					                Self::bitmap_win_into_packet(origin, pixels, compression)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Command::BitmapLinear(offset, bits, compression) => {
 | 
				
			||||||
 | 
					                Self::bitmap_linear_into_packet(
 | 
				
			||||||
 | 
					                    CommandCode::BitmapLinear,
 | 
				
			||||||
 | 
					                    offset,
 | 
				
			||||||
 | 
					                    compression,
 | 
				
			||||||
 | 
					                    bits.into(),
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Command::BitmapLinearAnd(offset, bits, compression) => {
 | 
				
			||||||
 | 
					                Self::bitmap_linear_into_packet(
 | 
				
			||||||
 | 
					                    CommandCode::BitmapLinearAnd,
 | 
				
			||||||
 | 
					                    offset,
 | 
				
			||||||
 | 
					                    compression,
 | 
				
			||||||
 | 
					                    bits.into(),
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Command::BitmapLinearOr(offset, bits, compression) => {
 | 
				
			||||||
 | 
					                Self::bitmap_linear_into_packet(
 | 
				
			||||||
 | 
					                    CommandCode::BitmapLinearOr,
 | 
				
			||||||
 | 
					                    offset,
 | 
				
			||||||
 | 
					                    compression,
 | 
				
			||||||
 | 
					                    bits.into(),
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Command::BitmapLinearXor(offset, bits, compression) => {
 | 
				
			||||||
 | 
					                Self::bitmap_linear_into_packet(
 | 
				
			||||||
 | 
					                    CommandCode::BitmapLinearXor,
 | 
				
			||||||
 | 
					                    offset,
 | 
				
			||||||
 | 
					                    compression,
 | 
				
			||||||
 | 
					                    bits.into(),
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Command::Cp437Data(origin, grid) => Packet(
 | 
				
			||||||
 | 
					                Header(
 | 
				
			||||||
 | 
					                    CommandCode::Cp437Data.into(),
 | 
				
			||||||
 | 
					                    origin.x as u16,
 | 
				
			||||||
 | 
					                    origin.y as u16,
 | 
				
			||||||
 | 
					                    grid.width() as u16,
 | 
				
			||||||
 | 
					                    grid.height() as u16,
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                grid.into(),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Packet {
 | 
				
			||||||
 | 
					    /// Helper method for `BitMapLinear*`-Commands into `Packet`
 | 
				
			||||||
 | 
					    #[allow(clippy::cast_possible_truncation)]
 | 
				
			||||||
 | 
					    fn bitmap_linear_into_packet(
 | 
				
			||||||
 | 
					        command: CommandCode,
 | 
				
			||||||
 | 
					        offset: Offset,
 | 
				
			||||||
 | 
					        compression: CompressionCode,
 | 
				
			||||||
 | 
					        payload: Vec<u8>,
 | 
				
			||||||
 | 
					    ) -> Packet {
 | 
				
			||||||
 | 
					        let length = payload.len() as u16;
 | 
				
			||||||
 | 
					        let payload = into_compressed(compression, payload);
 | 
				
			||||||
 | 
					        Packet(
 | 
				
			||||||
 | 
					            Header(
 | 
				
			||||||
 | 
					                command.into(),
 | 
				
			||||||
 | 
					                offset as u16,
 | 
				
			||||||
 | 
					                length,
 | 
				
			||||||
 | 
					                compression.into(),
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            payload,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[allow(clippy::cast_possible_truncation)]
 | 
				
			||||||
 | 
					    fn bitmap_win_into_packet(
 | 
				
			||||||
 | 
					        origin: Origin<Pixels>,
 | 
				
			||||||
 | 
					        pixels: PixelGrid,
 | 
				
			||||||
 | 
					        compression: CompressionCode,
 | 
				
			||||||
 | 
					    ) -> Packet {
 | 
				
			||||||
 | 
					        debug_assert_eq!(origin.x % 8, 0);
 | 
				
			||||||
 | 
					        debug_assert_eq!(pixels.width() % 8, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let tile_x = (origin.x / TILE_SIZE) as u16;
 | 
				
			||||||
 | 
					        let tile_w = (pixels.width() / TILE_SIZE) as u16;
 | 
				
			||||||
 | 
					        let pixel_h = pixels.height() as u16;
 | 
				
			||||||
 | 
					        let payload = into_compressed(compression, pixels.into());
 | 
				
			||||||
 | 
					        let command = match compression {
 | 
				
			||||||
 | 
					            CompressionCode::Uncompressed => {
 | 
				
			||||||
 | 
					                CommandCode::BitmapLinearWinUncompressed
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            #[cfg(feature = "compression_zlib")]
 | 
				
			||||||
 | 
					            CompressionCode::Zlib => CommandCode::BitmapLinearWinZlib,
 | 
				
			||||||
 | 
					            #[cfg(feature = "compression_bzip2")]
 | 
				
			||||||
 | 
					            CompressionCode::Bzip2 => CommandCode::BitmapLinearWinBzip2,
 | 
				
			||||||
 | 
					            #[cfg(feature = "compression_lzma")]
 | 
				
			||||||
 | 
					            CompressionCode::Lzma => CommandCode::BitmapLinearWinLzma,
 | 
				
			||||||
 | 
					            #[cfg(feature = "compression_zstd")]
 | 
				
			||||||
 | 
					            CompressionCode::Zstd => CommandCode::BitmapLinearWinZstd,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Packet(
 | 
				
			||||||
 | 
					            Header(command.into(), tile_x, origin.y as u16, tile_w, pixel_h),
 | 
				
			||||||
 | 
					            payload,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Helper method for creating empty packets only containing the command code
 | 
				
			||||||
 | 
					    fn command_code_only(code: CommandCode) -> Packet {
 | 
				
			||||||
 | 
					        Packet(Header(code.into(), 0x0000, 0x0000, 0x0000, 0x0000), vec![])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use crate::{Header, Packet};
 | 
					    use crate::{Header, Packet};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -158,7 +158,7 @@ impl Grid<bool> for PixelGrid {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl DataRef for PixelGrid {
 | 
					impl DataRef<u8> for PixelGrid {
 | 
				
			||||||
    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()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,40 +2,43 @@ use std::slice::{Iter, IterMut};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{DataRef, Grid};
 | 
					use crate::{DataRef, Grid};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait PrimitiveGridType: Sized + Default + Copy + Clone {}
 | 
				
			||||||
 | 
					impl<T: Sized + Default + Copy + Clone> PrimitiveGridType for T {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A 2D grid of bytes
 | 
					/// A 2D grid of bytes
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
pub struct ByteGrid {
 | 
					pub struct PrimitiveGrid<T: PrimitiveGridType> {
 | 
				
			||||||
    width: usize,
 | 
					    width: usize,
 | 
				
			||||||
    height: usize,
 | 
					    height: usize,
 | 
				
			||||||
    data: Vec<u8>,
 | 
					    data: Vec<T>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ByteGrid {
 | 
					impl<T: PrimitiveGridType> PrimitiveGrid<T> {
 | 
				
			||||||
    /// Creates a new `ByteGrid` with the specified dimensions.
 | 
					    /// Creates a new `PrimitiveGrid` with the specified dimensions.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// # Arguments
 | 
					    /// # Arguments
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// - width: size in x-direction
 | 
					    /// - width: size in x-direction
 | 
				
			||||||
    /// - height: size in y-direction
 | 
					    /// - height: size in y-direction
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// returns: `ByteGrid` initialized to 0.
 | 
					    /// returns: `PrimitiveGrid` initialized to default value.
 | 
				
			||||||
    pub fn new(width: usize, height: usize) -> Self {
 | 
					    pub fn new(width: usize, height: usize) -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            data: vec![0; width * height],
 | 
					            data: vec![Default::default(); width * height],
 | 
				
			||||||
            width,
 | 
					            width,
 | 
				
			||||||
            height,
 | 
					            height,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Loads a `ByteGrid` with the specified dimensions from the provided data.
 | 
					    /// Loads a `PrimitiveGrid` with the specified dimensions from the provided data.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// returns: `ByteGrid` that contains a copy of the provided data
 | 
					    /// returns: `PrimitiveGrid` that contains a copy of the provided data
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// # Panics
 | 
					    /// # Panics
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// - when the dimensions and data size do not match exactly.
 | 
					    /// - when the dimensions and data size do not match exactly.
 | 
				
			||||||
    #[must_use]
 | 
					    #[must_use]
 | 
				
			||||||
    pub fn load(width: usize, height: usize, data: &[u8]) -> Self {
 | 
					    pub fn load(width: usize, height: usize, data: &[T]) -> Self {
 | 
				
			||||||
        assert_eq!(width * height, data.len());
 | 
					        assert_eq!(width * height, data.len());
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            data: Vec::from(data),
 | 
					            data: Vec::from(data),
 | 
				
			||||||
| 
						 | 
					@ -44,24 +47,24 @@ impl ByteGrid {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Iterate over all cells in `ByteGrid`.
 | 
					    /// Iterate over all cells in `PrimitiveGrid`.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// Order is equivalent to the following loop:
 | 
					    /// Order is equivalent to the following loop:
 | 
				
			||||||
    /// ```
 | 
					    /// ```
 | 
				
			||||||
    /// # use servicepoint::{ByteGrid, Grid};
 | 
					    /// # use servicepoint::{PrimitiveGrid, Grid};
 | 
				
			||||||
    /// # let grid = ByteGrid::new(2,2);
 | 
					    /// # let grid = PrimitiveGrid::<u8>::new(2,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);
 | 
				
			||||||
    ///     }
 | 
					    ///     }
 | 
				
			||||||
    /// }
 | 
					    /// }
 | 
				
			||||||
    /// ```
 | 
					    /// ```
 | 
				
			||||||
    pub fn iter(&self) -> Iter<u8> {
 | 
					    pub fn iter(&self) -> Iter<T> {
 | 
				
			||||||
        self.data.iter()
 | 
					        self.data.iter()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Iterate over all rows in `ByteGrid` top to bottom.
 | 
					    /// Iterate over all rows in `PrimitiveGrid` top to bottom.
 | 
				
			||||||
    pub fn iter_rows(&self) -> IterRows {
 | 
					    pub fn iter_rows(&self) -> IterRows<T> {
 | 
				
			||||||
        IterRows {
 | 
					        IterRows {
 | 
				
			||||||
            byte_grid: self,
 | 
					            byte_grid: self,
 | 
				
			||||||
            row: 0,
 | 
					            row: 0,
 | 
				
			||||||
| 
						 | 
					@ -71,7 +74,7 @@ impl ByteGrid {
 | 
				
			||||||
    /// Returns an iterator that allows modifying each value.
 | 
					    /// Returns an iterator that allows modifying each value.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// The iterator yields all cells from top left to bottom right.
 | 
					    /// The iterator yields all cells from top left to bottom right.
 | 
				
			||||||
    pub fn iter_mut(&mut self) -> IterMut<u8> {
 | 
					    pub fn iter_mut(&mut self) -> IterMut<T> {
 | 
				
			||||||
        self.data.iter_mut()
 | 
					        self.data.iter_mut()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,7 +87,7 @@ impl ByteGrid {
 | 
				
			||||||
    /// # Panics
 | 
					    /// # Panics
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// When accessing `x` or `y` out of bounds.
 | 
					    /// When accessing `x` or `y` out of bounds.
 | 
				
			||||||
    pub fn get_ref_mut(&mut self, x: usize, y: usize) -> &mut u8 {
 | 
					    pub fn get_ref_mut(&mut self, x: usize, y: usize) -> &mut T {
 | 
				
			||||||
        self.assert_in_bounds(x, y);
 | 
					        self.assert_in_bounds(x, y);
 | 
				
			||||||
        &mut self.data[x + y * self.width]
 | 
					        &mut self.data[x + y * self.width]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -100,7 +103,7 @@ impl ByteGrid {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        x: isize,
 | 
					        x: isize,
 | 
				
			||||||
        y: isize,
 | 
					        y: isize,
 | 
				
			||||||
    ) -> Option<&mut u8> {
 | 
					    ) -> Option<&mut T> {
 | 
				
			||||||
        if self.is_in_bounds(x, y) {
 | 
					        if self.is_in_bounds(x, y) {
 | 
				
			||||||
            Some(&mut self.data[x as usize + y as usize * self.width])
 | 
					            Some(&mut self.data[x as usize + y as usize * self.width])
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
| 
						 | 
					@ -109,8 +112,8 @@ impl ByteGrid {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Grid<u8> for ByteGrid {
 | 
					impl<T: PrimitiveGridType> Grid<T> for PrimitiveGrid<T> {
 | 
				
			||||||
    /// Sets the value of the cell at the specified position in the `ByteGrid.
 | 
					    /// Sets the value of the cell at the specified position in the `PrimitiveGrid.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// # Arguments
 | 
					    /// # Arguments
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
| 
						 | 
					@ -120,7 +123,7 @@ impl Grid<u8> for ByteGrid {
 | 
				
			||||||
    /// # Panics
 | 
					    /// # Panics
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// When accessing `x` or `y` out of bounds.
 | 
					    /// When accessing `x` or `y` out of bounds.
 | 
				
			||||||
    fn set(&mut self, x: usize, y: usize, value: u8) {
 | 
					    fn set(&mut self, x: usize, y: usize, value: T) {
 | 
				
			||||||
        self.assert_in_bounds(x, y);
 | 
					        self.assert_in_bounds(x, y);
 | 
				
			||||||
        self.data[x + y * self.width] = value;
 | 
					        self.data[x + y * self.width] = value;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -134,12 +137,12 @@ impl Grid<u8> for ByteGrid {
 | 
				
			||||||
    /// # Panics
 | 
					    /// # Panics
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// When accessing `x` or `y` out of bounds.
 | 
					    /// When accessing `x` or `y` out of bounds.
 | 
				
			||||||
    fn get(&self, x: usize, y: usize) -> u8 {
 | 
					    fn get(&self, x: usize, y: usize) -> T {
 | 
				
			||||||
        self.assert_in_bounds(x, y);
 | 
					        self.assert_in_bounds(x, y);
 | 
				
			||||||
        self.data[x + y * self.width]
 | 
					        self.data[x + y * self.width]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn fill(&mut self, value: u8) {
 | 
					    fn fill(&mut self, value: T) {
 | 
				
			||||||
        self.data.fill(value);
 | 
					        self.data.fill(value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -152,32 +155,32 @@ impl Grid<u8> for ByteGrid {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl DataRef for ByteGrid {
 | 
					impl<T: PrimitiveGridType> DataRef<T> for PrimitiveGrid<T> {
 | 
				
			||||||
    /// Get the underlying byte rows mutable
 | 
					    /// Get the underlying byte rows mutable
 | 
				
			||||||
    fn data_ref_mut(&mut self) -> &mut [u8] {
 | 
					    fn data_ref_mut(&mut self) -> &mut [T] {
 | 
				
			||||||
        self.data.as_mut_slice()
 | 
					        self.data.as_mut_slice()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Get the underlying byte rows read only
 | 
					    /// Get the underlying byte rows read only
 | 
				
			||||||
    fn data_ref(&self) -> &[u8] {
 | 
					    fn data_ref(&self) -> &[T] {
 | 
				
			||||||
        self.data.as_slice()
 | 
					        self.data.as_slice()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl From<ByteGrid> for Vec<u8> {
 | 
					impl<T: PrimitiveGridType> From<PrimitiveGrid<T>> for Vec<T> {
 | 
				
			||||||
    /// Turn into the underlying `Vec<u8>` containing the rows of bytes.
 | 
					    /// Turn into the underlying `Vec<u8>` containing the rows of bytes.
 | 
				
			||||||
    fn from(value: ByteGrid) -> Self {
 | 
					    fn from(value: PrimitiveGrid<T>) -> Self {
 | 
				
			||||||
        value.data
 | 
					        value.data
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct IterRows<'t> {
 | 
					pub struct IterRows<'t, T: PrimitiveGridType> {
 | 
				
			||||||
    byte_grid: &'t ByteGrid,
 | 
					    byte_grid: &'t PrimitiveGrid<T>,
 | 
				
			||||||
    row: usize,
 | 
					    row: usize,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'t> Iterator for IterRows<'t> {
 | 
					impl<'t, T: PrimitiveGridType> Iterator for IterRows<'t, T> {
 | 
				
			||||||
    type Item = Iter<'t, u8>;
 | 
					    type Item = Iter<'t, T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
					    fn next(&mut self) -> Option<Self::Item> {
 | 
				
			||||||
        if self.row >= self.byte_grid.height {
 | 
					        if self.row >= self.byte_grid.height {
 | 
				
			||||||
| 
						 | 
					@ -194,11 +197,11 @@ impl<'t> Iterator for IterRows<'t> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use crate::{ByteGrid, DataRef, Grid};
 | 
					    use crate::{DataRef, Grid, PrimitiveGrid};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn fill() {
 | 
					    fn fill() {
 | 
				
			||||||
        let mut grid = ByteGrid::new(2, 2);
 | 
					        let mut grid = PrimitiveGrid::<usize>::new(2, 2);
 | 
				
			||||||
        assert_eq!(grid.data, [0x00, 0x00, 0x00, 0x00]);
 | 
					        assert_eq!(grid.data, [0x00, 0x00, 0x00, 0x00]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        grid.fill(42);
 | 
					        grid.fill(42);
 | 
				
			||||||
| 
						 | 
					@ -207,7 +210,7 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn get_set() {
 | 
					    fn get_set() {
 | 
				
			||||||
        let mut grid = ByteGrid::new(2, 2);
 | 
					        let mut grid = PrimitiveGrid::new(2, 2);
 | 
				
			||||||
        assert_eq!(grid.get(0, 0), 0);
 | 
					        assert_eq!(grid.get(0, 0), 0);
 | 
				
			||||||
        assert_eq!(grid.get(1, 1), 0);
 | 
					        assert_eq!(grid.get(1, 1), 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -222,7 +225,7 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn load() {
 | 
					    fn load() {
 | 
				
			||||||
        let mut grid = ByteGrid::new(2, 3);
 | 
					        let mut grid = PrimitiveGrid::new(2, 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) as u8);
 | 
					                grid.set(x, y, (x + y) as u8);
 | 
				
			||||||
| 
						 | 
					@ -233,13 +236,13 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let data: Vec<u8> = grid.into();
 | 
					        let data: Vec<u8> = grid.into();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let grid = ByteGrid::load(2, 3, &data);
 | 
					        let grid = PrimitiveGrid::load(2, 3, &data);
 | 
				
			||||||
        assert_eq!(grid.data, [0, 1, 1, 2, 2, 3]);
 | 
					        assert_eq!(grid.data, [0, 1, 1, 2, 2, 3]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn mut_data_ref() {
 | 
					    fn mut_data_ref() {
 | 
				
			||||||
        let mut vec = ByteGrid::new(2, 2);
 | 
					        let mut vec = PrimitiveGrid::new(2, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let data_ref = vec.data_ref_mut();
 | 
					        let data_ref = vec.data_ref_mut();
 | 
				
			||||||
        data_ref.copy_from_slice(&[1, 2, 3, 4]);
 | 
					        data_ref.copy_from_slice(&[1, 2, 3, 4]);
 | 
				
			||||||
| 
						 | 
					@ -250,7 +253,7 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn iter() {
 | 
					    fn iter() {
 | 
				
			||||||
        let mut vec = ByteGrid::new(2, 2);
 | 
					        let mut vec = PrimitiveGrid::new(2, 2);
 | 
				
			||||||
        vec.set(1, 1, 5);
 | 
					        vec.set(1, 1, 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut iter = vec.iter();
 | 
					        let mut iter = vec.iter();
 | 
				
			||||||
| 
						 | 
					@ -262,7 +265,7 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn iter_mut() {
 | 
					    fn iter_mut() {
 | 
				
			||||||
        let mut vec = ByteGrid::new(2, 3);
 | 
					        let mut vec = PrimitiveGrid::new(2, 3);
 | 
				
			||||||
        for (index, cell) in vec.iter_mut().enumerate() {
 | 
					        for (index, cell) in vec.iter_mut().enumerate() {
 | 
				
			||||||
            *cell = index as u8;
 | 
					            *cell = index as u8;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -272,7 +275,7 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn iter_rows() {
 | 
					    fn iter_rows() {
 | 
				
			||||||
        let vec = ByteGrid::load(2, 3, &[0, 1, 1, 2, 2, 3]);
 | 
					        let vec = PrimitiveGrid::load(2, 3, &[0, 1, 1, 2, 2, 3]);
 | 
				
			||||||
        for (y, row) in vec.iter_rows().enumerate() {
 | 
					        for (y, row) in vec.iter_rows().enumerate() {
 | 
				
			||||||
            for (x, val) in row.enumerate() {
 | 
					            for (x, val) in row.enumerate() {
 | 
				
			||||||
                assert_eq!(*val, (x + y) as u8);
 | 
					                assert_eq!(*val, (x + y) as u8);
 | 
				
			||||||
| 
						 | 
					@ -283,20 +286,20 @@ mod tests {
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    #[should_panic]
 | 
					    #[should_panic]
 | 
				
			||||||
    fn out_of_bounds_x() {
 | 
					    fn out_of_bounds_x() {
 | 
				
			||||||
        let mut vec = ByteGrid::load(2, 2, &[0, 1, 2, 3]);
 | 
					        let mut vec = PrimitiveGrid::load(2, 2, &[0, 1, 2, 3]);
 | 
				
			||||||
        vec.set(2, 1, 5);
 | 
					        vec.set(2, 1, 5);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    #[should_panic]
 | 
					    #[should_panic]
 | 
				
			||||||
    fn out_of_bounds_y() {
 | 
					    fn out_of_bounds_y() {
 | 
				
			||||||
        let vec = ByteGrid::load(2, 2, &[0, 1, 2, 3]);
 | 
					        let vec = PrimitiveGrid::load(2, 2, &[0, 1, 2, 3]);
 | 
				
			||||||
        vec.get(1, 2);
 | 
					        vec.get(1, 2);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn ref_mut() {
 | 
					    fn ref_mut() {
 | 
				
			||||||
        let mut vec = ByteGrid::load(2, 2, &[0, 1, 2, 3]);
 | 
					        let mut vec = PrimitiveGrid::load(2, 2, &[0, 1, 2, 3]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let top_left = vec.get_ref_mut(0, 0);
 | 
					        let top_left = vec.get_ref_mut(0, 0);
 | 
				
			||||||
        *top_left += 5;
 | 
					        *top_left += 5;
 | 
				
			||||||
| 
						 | 
					@ -307,7 +310,7 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn optional() {
 | 
					    fn optional() {
 | 
				
			||||||
        let mut grid = ByteGrid::load(2, 2, &[0, 1, 2, 3]);
 | 
					        let mut grid = PrimitiveGrid::load(2, 2, &[0, 1, 2, 3]);
 | 
				
			||||||
        grid.set_optional(0, 0, 5);
 | 
					        grid.set_optional(0, 0, 5);
 | 
				
			||||||
        grid.set_optional(-1, 0, 8);
 | 
					        grid.set_optional(-1, 0, 8);
 | 
				
			||||||
        grid.set_optional(0, 8, 42);
 | 
					        grid.set_optional(0, 8, 42);
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,7 @@ crate-type = ["staticlib", "cdylib", "rlib"]
 | 
				
			||||||
cbindgen = "0.26.0"
 | 
					cbindgen = "0.26.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies.servicepoint]
 | 
					[dependencies.servicepoint]
 | 
				
			||||||
version = "0.6.0"
 | 
					version = "0.7.0"
 | 
				
			||||||
path = "../servicepoint"
 | 
					path = "../servicepoint"
 | 
				
			||||||
features = ["all_compressions"]
 | 
					features = ["all_compressions"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,4 +33,4 @@ include = ["servicepoint"]
 | 
				
			||||||
extra_bindings = ["servicepoint"]
 | 
					extra_bindings = ["servicepoint"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[parse.expand]
 | 
					[parse.expand]
 | 
				
			||||||
#all_features = true
 | 
					all_features = true
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,14 +70,18 @@ typedef uint16_t sp_CompressionCode;
 | 
				
			||||||
#endif // __cplusplus
 | 
					#endif // __cplusplus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A fixed-size vector of bits
 | 
					 * A display brightness value, checked for correct value range
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef struct sp_BitVec sp_BitVec;
 | 
					typedef struct sp_Brightness sp_Brightness;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A 2D grid of bytes
 | 
					 * Opaque struct needed for correct code generation.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef struct sp_ByteGrid sp_ByteGrid;
 | 
					typedef struct sp_CBitVec sp_CBitVec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct sp_CBrightnessGrid sp_CBrightnessGrid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct sp_CCp437Grid sp_CCp437Grid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A command to send to the display.
 | 
					 * A command to send to the display.
 | 
				
			||||||
| 
						 | 
					@ -99,6 +103,16 @@ typedef struct sp_Packet sp_Packet;
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef struct sp_PixelGrid sp_PixelGrid;
 | 
					typedef struct sp_PixelGrid sp_PixelGrid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A 2D grid of bytes
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct sp_PrimitiveGrid_Brightness sp_PrimitiveGrid_Brightness;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A 2D grid of bytes
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct sp_PrimitiveGrid_u8 sp_PrimitiveGrid_u8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 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.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -127,9 +141,20 @@ typedef struct sp_CByteSlice {
 | 
				
			||||||
typedef size_t sp_Offset;
 | 
					typedef size_t sp_Offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Type alias for documenting the meaning of the u16 in enum values
 | 
					 * A grid containing brightness values.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef uint8_t sp_Brightness;
 | 
					typedef struct sp_PrimitiveGrid_Brightness sp_BrightnessGrid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A grid containing codepage 437 characters.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The encoding is currently not enforced.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct sp_PrimitiveGrid_u8 sp_Cp437Grid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __cplusplus
 | 
					#ifdef __cplusplus
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
| 
						 | 
					@ -147,7 +172,7 @@ extern "C" {
 | 
				
			||||||
 * - 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_dealloc`.
 | 
					 *   by explicitly calling `sp_bit_vec_dealloc`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_BitVec *sp_bit_vec_clone(const struct sp_BitVec *this_);
 | 
					struct sp_CBitVec *sp_bit_vec_clone(const struct sp_CBitVec *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Deallocates a `BitVec`.
 | 
					 * Deallocates a `BitVec`.
 | 
				
			||||||
| 
						 | 
					@ -160,7 +185,7 @@ struct sp_BitVec *sp_bit_vec_clone(const struct sp_BitVec *this_);
 | 
				
			||||||
 * - `this` is not used concurrently or after this call
 | 
					 * - `this` is not used concurrently or after this call
 | 
				
			||||||
 * - `this` was not passed to another consuming function, e.g. to create a `Command`
 | 
					 * - `this` was not passed to another consuming function, e.g. to create a `Command`
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void sp_bit_vec_dealloc(struct sp_BitVec *this_);
 | 
					void sp_bit_vec_dealloc(struct sp_CBitVec *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Sets the value of all bits in the `BitVec`.
 | 
					 * Sets the value of all bits in the `BitVec`.
 | 
				
			||||||
| 
						 | 
					@ -176,7 +201,7 @@ void sp_bit_vec_dealloc(struct sp_BitVec *this_);
 | 
				
			||||||
 * - `this` points to a valid `BitVec`
 | 
					 * - `this` points to a valid `BitVec`
 | 
				
			||||||
 * - `this` is not written to or read from concurrently
 | 
					 * - `this` is not written to or read from concurrently
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void sp_bit_vec_fill(struct sp_BitVec *this_, bool value);
 | 
					void sp_bit_vec_fill(struct sp_CBitVec *this_, bool value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Gets the value of a bit from the `BitVec`.
 | 
					 * Gets the value of a bit from the `BitVec`.
 | 
				
			||||||
| 
						 | 
					@ -199,7 +224,7 @@ void sp_bit_vec_fill(struct sp_BitVec *this_, bool value);
 | 
				
			||||||
 * - `this` points to a valid `BitVec`
 | 
					 * - `this` points to a valid `BitVec`
 | 
				
			||||||
 * - `this` is not written to concurrently
 | 
					 * - `this` is not written to concurrently
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool sp_bit_vec_get(const struct sp_BitVec *this_, size_t index);
 | 
					bool sp_bit_vec_get(const struct sp_CBitVec *this_, size_t index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Returns true if length is 0.
 | 
					 * Returns true if length is 0.
 | 
				
			||||||
| 
						 | 
					@ -210,7 +235,7 @@ bool sp_bit_vec_get(const struct sp_BitVec *this_, size_t index);
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - `this` points to a valid `BitVec`
 | 
					 * - `this` points to a valid `BitVec`
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool sp_bit_vec_is_empty(const struct sp_BitVec *this_);
 | 
					bool sp_bit_vec_is_empty(const struct sp_CBitVec *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Gets the length of the `BitVec` in bits.
 | 
					 * Gets the length of the `BitVec` in bits.
 | 
				
			||||||
| 
						 | 
					@ -221,7 +246,7 @@ bool sp_bit_vec_is_empty(const struct sp_BitVec *this_);
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - `this` points to a valid `BitVec`
 | 
					 * - `this` points to a valid `BitVec`
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
size_t sp_bit_vec_len(const struct sp_BitVec *this_);
 | 
					size_t sp_bit_vec_len(const struct sp_CBitVec *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Interpret the data as a series of bits and load then into a new `BitVec` instance.
 | 
					 * Interpret the data as a series of bits and load then into a new `BitVec` instance.
 | 
				
			||||||
| 
						 | 
					@ -235,7 +260,7 @@ size_t sp_bit_vec_len(const struct sp_BitVec *this_);
 | 
				
			||||||
 * - 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_dealloc`.
 | 
					 *   by explicitly calling `sp_bit_vec_dealloc`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_BitVec *sp_bit_vec_load(const uint8_t *data,
 | 
					struct sp_CBitVec *sp_bit_vec_load(const uint8_t *data,
 | 
				
			||||||
                                   size_t data_length);
 | 
					                                   size_t data_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -258,7 +283,7 @@ struct sp_BitVec *sp_bit_vec_load(const uint8_t *data,
 | 
				
			||||||
 * - 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_dealloc`.
 | 
					 *   by explicitly calling `sp_bit_vec_dealloc`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_BitVec *sp_bit_vec_new(size_t size);
 | 
					struct sp_CBitVec *sp_bit_vec_new(size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Sets the value of a bit in the `BitVec`.
 | 
					 * Sets the value of a bit in the `BitVec`.
 | 
				
			||||||
| 
						 | 
					@ -282,7 +307,7 @@ struct sp_BitVec *sp_bit_vec_new(size_t size);
 | 
				
			||||||
 * - `this` points to a valid `BitVec`
 | 
					 * - `this` points to a valid `BitVec`
 | 
				
			||||||
 * - `this` is not written to or read from concurrently
 | 
					 * - `this` is not written to or read from concurrently
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool sp_bit_vec_set(struct sp_BitVec *this_, size_t index, bool value);
 | 
					void sp_bit_vec_set(struct sp_CBitVec *this_, size_t index, bool value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Gets an unsafe reference to the data of the `BitVec` instance.
 | 
					 * Gets an unsafe reference to the data of the `BitVec` instance.
 | 
				
			||||||
| 
						 | 
					@ -295,37 +320,37 @@ bool sp_bit_vec_set(struct sp_BitVec *this_, size_t index, bool value);
 | 
				
			||||||
 * - the returned memory range is never accessed after the passed `BitVec` has been freed
 | 
					 * - the returned memory range is never accessed after the passed `BitVec` has been freed
 | 
				
			||||||
 * - the returned memory range is never accessed concurrently, either via the `BitVec` or directly
 | 
					 * - the returned memory range is never accessed concurrently, either via the `BitVec` or directly
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_CByteSlice sp_bit_vec_unsafe_data_ref(struct sp_BitVec *this_);
 | 
					struct sp_CByteSlice sp_bit_vec_unsafe_data_ref(struct sp_CBitVec *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Clones a `ByteGrid`.
 | 
					 * Clones a `BrightnessGrid`.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * # Safety
 | 
					 * # Safety
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The caller has to make sure that:
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - `this` points to a valid `ByteGrid`
 | 
					 * - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 * - `this` is not written to concurrently
 | 
					 * - `this` 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_byte_grid_dealloc`.
 | 
					 *   by explicitly calling `sp_brightness_grid_dealloc`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_ByteGrid *sp_byte_grid_clone(const struct sp_ByteGrid *this_);
 | 
					struct sp_CBrightnessGrid *sp_brightness_grid_clone(const struct sp_CBrightnessGrid *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Deallocates a `ByteGrid`.
 | 
					 * Deallocates a `BrightnessGrid`.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * # Safety
 | 
					 * # Safety
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The caller has to make sure that:
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - `this` points to a valid `ByteGrid`
 | 
					 * - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 * - `this` is not used concurrently or after this call
 | 
					 * - `this` is not used concurrently or after this call
 | 
				
			||||||
 * - `this` was not passed to another consuming function, e.g. to create a `Command`
 | 
					 * - `this` was not passed to another consuming function, e.g. to create a `Command`
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void sp_byte_grid_dealloc(struct sp_ByteGrid *this_);
 | 
					void sp_brightness_grid_dealloc(struct sp_CBrightnessGrid *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Sets the value of all cells in the `ByteGrid`.
 | 
					 * Sets the value of all cells in the `BrightnessGrid`.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * # Arguments
 | 
					 * # Arguments
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -336,10 +361,10 @@ void sp_byte_grid_dealloc(struct sp_ByteGrid *this_);
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The caller has to make sure that:
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - `this` points to a valid `ByteGrid`
 | 
					 * - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 * - `this` is not written to or read from concurrently
 | 
					 * - `this` is not written to or read from concurrently
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void sp_byte_grid_fill(struct sp_ByteGrid *this_, uint8_t value);
 | 
					void sp_brightness_grid_fill(struct sp_CBrightnessGrid *this_, uint8_t value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Gets the current value at the specified position.
 | 
					 * Gets the current value at the specified position.
 | 
				
			||||||
| 
						 | 
					@ -357,13 +382,15 @@ void sp_byte_grid_fill(struct sp_ByteGrid *this_, uint8_t value);
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The caller has to make sure that:
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - `this` points to a valid `ByteGrid`
 | 
					 * - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 * - `this` is not written to concurrently
 | 
					 * - `this` is not written to concurrently
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
uint8_t sp_byte_grid_get(const struct sp_ByteGrid *this_, size_t x, size_t y);
 | 
					uint8_t sp_brightness_grid_get(const struct sp_CBrightnessGrid *this_,
 | 
				
			||||||
 | 
					                               size_t x,
 | 
				
			||||||
 | 
					                               size_t y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Gets the height of the `ByteGrid` instance.
 | 
					 * Gets the height of the `BrightnessGrid` instance.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * # Arguments
 | 
					 * # Arguments
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -373,12 +400,12 @@ uint8_t sp_byte_grid_get(const struct sp_ByteGrid *this_, size_t x, size_t y);
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The caller has to make sure that:
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - `this` points to a valid `ByteGrid`
 | 
					 * - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
size_t sp_byte_grid_height(const struct sp_ByteGrid *this_);
 | 
					size_t sp_brightness_grid_height(const struct sp_CBrightnessGrid *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Loads a `ByteGrid` with the specified dimensions from the provided data.
 | 
					 * Loads a `BrightnessGrid` with the specified dimensions from the provided data.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * # Panics
 | 
					 * # Panics
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -391,30 +418,30 @@ size_t sp_byte_grid_height(const struct sp_ByteGrid *this_);
 | 
				
			||||||
 * - `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_byte_grid_dealloc`.
 | 
					 *   by explicitly calling `sp_brightness_grid_dealloc`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_ByteGrid *sp_byte_grid_load(size_t width,
 | 
					struct sp_CBrightnessGrid *sp_brightness_grid_load(size_t width,
 | 
				
			||||||
                                                   size_t height,
 | 
					                                                   size_t height,
 | 
				
			||||||
                                                   const uint8_t *data,
 | 
					                                                   const uint8_t *data,
 | 
				
			||||||
                                                   size_t data_length);
 | 
					                                                   size_t data_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Creates a new `ByteGrid` with the specified dimensions.
 | 
					 * Creates a new `BrightnessGrid` with the specified dimensions.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * returns: `ByteGrid` initialized to 0.
 | 
					 * returns: `BrightnessGrid` initialized to 0.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * # 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_byte_grid_dealloc`.
 | 
					 *   by explicitly calling `sp_brightness_grid_dealloc`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_ByteGrid *sp_byte_grid_new(size_t width,
 | 
					struct sp_CBrightnessGrid *sp_brightness_grid_new(size_t width,
 | 
				
			||||||
                                                  size_t height);
 | 
					                                                  size_t height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Sets the value of the specified position in the `ByteGrid`.
 | 
					 * Sets the value of the specified position in the `BrightnessGrid`.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * # Arguments
 | 
					 * # Arguments
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -435,26 +462,26 @@ struct sp_ByteGrid *sp_byte_grid_new(size_t width,
 | 
				
			||||||
 * - `this` points to a valid `BitVec`
 | 
					 * - `this` points to a valid `BitVec`
 | 
				
			||||||
 * - `this` is not written to or read from concurrently
 | 
					 * - `this` is not written to or read from concurrently
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void sp_byte_grid_set(struct sp_ByteGrid *this_,
 | 
					void sp_brightness_grid_set(struct sp_CBrightnessGrid *this_,
 | 
				
			||||||
                            size_t x,
 | 
					                            size_t x,
 | 
				
			||||||
                            size_t y,
 | 
					                            size_t y,
 | 
				
			||||||
                            uint8_t value);
 | 
					                            uint8_t value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Gets an unsafe reference to the data of the `ByteGrid` instance.
 | 
					 * Gets an unsafe reference to the data of the `BrightnessGrid` instance.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * ## Safety
 | 
					 * ## Safety
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The caller has to make sure that:
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - `this` points to a valid `ByteGrid`
 | 
					 * - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 * - the returned memory range is never accessed after the passed `ByteGrid` has been freed
 | 
					 * - the returned memory range is never accessed after the passed `BrightnessGrid` has been freed
 | 
				
			||||||
 * - the returned memory range is never accessed concurrently, either via the `ByteGrid` or directly
 | 
					 * - the returned memory range is never accessed concurrently, either via the `BrightnessGrid` or directly
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_CByteSlice sp_byte_grid_unsafe_data_ref(struct sp_ByteGrid *this_);
 | 
					struct sp_CByteSlice sp_brightness_grid_unsafe_data_ref(struct sp_CBrightnessGrid *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Gets the width of the `ByteGrid` instance.
 | 
					 * Gets the width of the `BrightnessGrid` instance.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * # Arguments
 | 
					 * # Arguments
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -464,9 +491,9 @@ struct sp_CByteSlice sp_byte_grid_unsafe_data_ref(struct sp_ByteGrid *this_);
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The caller has to make sure that:
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - `this` points to a valid `ByteGrid`
 | 
					 * - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
size_t sp_byte_grid_width(const struct sp_ByteGrid *this_);
 | 
					size_t sp_brightness_grid_width(const struct sp_CBrightnessGrid *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Allocates a new `Command::BitmapLinear` instance.
 | 
					 * Allocates a new `Command::BitmapLinear` instance.
 | 
				
			||||||
| 
						 | 
					@ -483,7 +510,7 @@ size_t sp_byte_grid_width(const struct sp_ByteGrid *this_);
 | 
				
			||||||
 *   by explicitly calling `sp_command_dealloc`.
 | 
					 *   by explicitly calling `sp_command_dealloc`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_Command *sp_command_bitmap_linear(sp_Offset offset,
 | 
					struct sp_Command *sp_command_bitmap_linear(sp_Offset offset,
 | 
				
			||||||
                                            struct sp_BitVec *bit_vec,
 | 
					                                            struct sp_CBitVec *bit_vec,
 | 
				
			||||||
                                            sp_CompressionCode compression);
 | 
					                                            sp_CompressionCode compression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -501,7 +528,7 @@ struct sp_Command *sp_command_bitmap_linear(sp_Offset offset,
 | 
				
			||||||
 *   by explicitly calling `sp_command_dealloc`.
 | 
					 *   by explicitly calling `sp_command_dealloc`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_Command *sp_command_bitmap_linear_and(sp_Offset offset,
 | 
					struct sp_Command *sp_command_bitmap_linear_and(sp_Offset offset,
 | 
				
			||||||
                                                struct sp_BitVec *bit_vec,
 | 
					                                                struct sp_CBitVec *bit_vec,
 | 
				
			||||||
                                                sp_CompressionCode compression);
 | 
					                                                sp_CompressionCode compression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -519,7 +546,7 @@ struct sp_Command *sp_command_bitmap_linear_and(sp_Offset offset,
 | 
				
			||||||
 *   by explicitly calling `sp_command_dealloc`.
 | 
					 *   by explicitly calling `sp_command_dealloc`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_Command *sp_command_bitmap_linear_or(sp_Offset offset,
 | 
					struct sp_Command *sp_command_bitmap_linear_or(sp_Offset offset,
 | 
				
			||||||
                                               struct sp_BitVec *bit_vec,
 | 
					                                               struct sp_CBitVec *bit_vec,
 | 
				
			||||||
                                               sp_CompressionCode compression);
 | 
					                                               sp_CompressionCode compression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -556,11 +583,16 @@ struct sp_Command *sp_command_bitmap_linear_win(size_t x,
 | 
				
			||||||
 *   by explicitly calling `sp_command_dealloc`.
 | 
					 *   by explicitly calling `sp_command_dealloc`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_Command *sp_command_bitmap_linear_xor(sp_Offset offset,
 | 
					struct sp_Command *sp_command_bitmap_linear_xor(sp_Offset offset,
 | 
				
			||||||
                                                struct sp_BitVec *bit_vec,
 | 
					                                                struct sp_CBitVec *bit_vec,
 | 
				
			||||||
                                                sp_CompressionCode compression);
 | 
					                                                sp_CompressionCode compression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Allocates a new `Command::Brightness` instance.
 | 
					 * Allocates a new `Command::Brightness` instance for setting the brightness of all tiles to the
 | 
				
			||||||
 | 
					 * same value.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Panics
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - When the provided brightness value is out of range (0-11).
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * # Safety
 | 
					 * # Safety
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -569,7 +601,7 @@ struct sp_Command *sp_command_bitmap_linear_xor(sp_Offset offset,
 | 
				
			||||||
 * - the returned `Command` instance is freed in some way, either by using a consuming function or
 | 
					 * - the returned `Command` instance is freed in some way, either by using a consuming function or
 | 
				
			||||||
 *   by explicitly calling `sp_command_dealloc`.
 | 
					 *   by explicitly calling `sp_command_dealloc`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_Command *sp_command_brightness(sp_Brightness brightness);
 | 
					struct sp_Command *sp_command_brightness(uint8_t brightness);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Allocates a new `Command::CharBrightness` instance.
 | 
					 * Allocates a new `Command::CharBrightness` instance.
 | 
				
			||||||
| 
						 | 
					@ -586,7 +618,7 @@ struct sp_Command *sp_command_brightness(sp_Brightness brightness);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_Command *sp_command_char_brightness(size_t x,
 | 
					struct sp_Command *sp_command_char_brightness(size_t x,
 | 
				
			||||||
                                              size_t y,
 | 
					                                              size_t y,
 | 
				
			||||||
                                              struct sp_ByteGrid *byte_grid);
 | 
					                                              sp_BrightnessGrid *byte_grid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Allocates a new `Command::Clear` instance.
 | 
					 * Allocates a new `Command::Clear` instance.
 | 
				
			||||||
| 
						 | 
					@ -629,7 +661,7 @@ struct sp_Command *sp_command_clone(const struct sp_Command *original);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sp_Command *sp_command_cp437_data(size_t x,
 | 
					struct sp_Command *sp_command_cp437_data(size_t x,
 | 
				
			||||||
                                         size_t y,
 | 
					                                         size_t y,
 | 
				
			||||||
                                         struct sp_ByteGrid *byte_grid);
 | 
					                                         sp_Cp437Grid *byte_grid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Deallocates a `Command`.
 | 
					 * Deallocates a `Command`.
 | 
				
			||||||
| 
						 | 
					@ -732,6 +764,179 @@ struct sp_Connection *sp_connection_open(const char *host);
 | 
				
			||||||
bool sp_connection_send(const struct sp_Connection *connection,
 | 
					bool sp_connection_send(const struct sp_Connection *connection,
 | 
				
			||||||
                        struct sp_Packet *packet);
 | 
					                        struct sp_Packet *packet);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Clones a `Cp437Grid`.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Safety
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
 | 
					 * - `this` is not written to concurrently
 | 
				
			||||||
 | 
					 * - the returned instance is freed in some way, either by using a consuming function or
 | 
				
			||||||
 | 
					 *   by explicitly calling `sp_cp437_grid_dealloc`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct sp_CCp437Grid *sp_cp437_grid_clone(const struct sp_CCp437Grid *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Deallocates a `Cp437Grid`.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Safety
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
 | 
					 * - `this` is not used concurrently or after this call
 | 
				
			||||||
 | 
					 * - `this` was not passed to another consuming function, e.g. to create a `Command`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void sp_cp437_grid_dealloc(struct sp_CCp437Grid *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Sets the value of all cells in the `Cp437Grid`.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Arguments
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * * `this`: instance to write to
 | 
				
			||||||
 | 
					 * * `value`: the value to set all cells to
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Safety
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
 | 
					 * - `this` is not written to or read from concurrently
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void sp_cp437_grid_fill(struct sp_CCp437Grid *this_, uint8_t value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Gets the current value at the specified position.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Arguments
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * * `this`: 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:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
 | 
					 * - `this` is not written to concurrently
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					uint8_t sp_cp437_grid_get(const struct sp_CCp437Grid *this_,
 | 
				
			||||||
 | 
					                          size_t x,
 | 
				
			||||||
 | 
					                          size_t y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Gets the height of the `Cp437Grid` instance.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Arguments
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * * `this`: instance to read from
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Safety
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					size_t sp_cp437_grid_height(const struct sp_CCp437Grid *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Loads a `Cp437Grid` with the specified dimensions from the provided data.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Panics
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * When the provided `data_length` is not sufficient for the `height` and `width`
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # 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_cp437_grid_dealloc`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct sp_CCp437Grid *sp_cp437_grid_load(size_t width,
 | 
				
			||||||
 | 
					                                         size_t height,
 | 
				
			||||||
 | 
					                                         const uint8_t *data,
 | 
				
			||||||
 | 
					                                         size_t data_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Creates a new `Cp437Grid` with the specified dimensions.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * returns: `Cp437Grid` initialized to 0.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # 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_cp437_grid_dealloc`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct sp_CCp437Grid *sp_cp437_grid_new(size_t width,
 | 
				
			||||||
 | 
					                                        size_t height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Sets the value of the specified position in the `Cp437Grid`.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Arguments
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * * `this`: 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:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - `this` points to a valid `BitVec`
 | 
				
			||||||
 | 
					 * - `this` is not written to or read from concurrently
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void sp_cp437_grid_set(struct sp_CCp437Grid *this_,
 | 
				
			||||||
 | 
					                       size_t x,
 | 
				
			||||||
 | 
					                       size_t y,
 | 
				
			||||||
 | 
					                       uint8_t value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Gets an unsafe reference to the data of the `Cp437Grid` instance.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * ## Safety
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
 | 
					 * - the returned memory range is never accessed after the passed `Cp437Grid` has been freed
 | 
				
			||||||
 | 
					 * - the returned memory range is never accessed concurrently, either via the `Cp437Grid` or directly
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct sp_CByteSlice sp_cp437_grid_unsafe_data_ref(struct sp_CCp437Grid *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Gets the width of the `Cp437Grid` instance.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Arguments
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * * `this`: instance to read from
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * # Safety
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The caller has to make sure that:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					size_t sp_cp437_grid_width(const struct sp_CCp437Grid *this_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Deallocates a `Packet`.
 | 
					 * Deallocates a `Packet`.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										233
									
								
								crates/servicepoint_binding_c/src/brightness_grid.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								crates/servicepoint_binding_c/src/brightness_grid.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,233 @@
 | 
				
			||||||
 | 
					//! C functions for interacting with `BrightnessGrid`s
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! prefix `sp_brightness_grid_`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use servicepoint::{Brightness, BrightnessGrid, DataRef, Grid, PrimitiveGrid};
 | 
				
			||||||
 | 
					use std::intrinsics::transmute;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::c_slice::CByteSlice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// C-wrapper for grid containing brightness values.
 | 
				
			||||||
 | 
					#[derive(Clone)]
 | 
				
			||||||
 | 
					pub struct CBrightnessGrid(pub(crate) BrightnessGrid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Creates a new `BrightnessGrid` with the specified dimensions.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// returns: `BrightnessGrid` initialized to 0.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # 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_brightness_grid_dealloc`.
 | 
				
			||||||
 | 
					#[no_mangle]
 | 
				
			||||||
 | 
					pub unsafe extern "C" fn sp_brightness_grid_new(
 | 
				
			||||||
 | 
					    width: usize,
 | 
				
			||||||
 | 
					    height: usize,
 | 
				
			||||||
 | 
					) -> *mut CBrightnessGrid {
 | 
				
			||||||
 | 
					    Box::into_raw(Box::new(CBrightnessGrid(BrightnessGrid::new(
 | 
				
			||||||
 | 
					        width, height,
 | 
				
			||||||
 | 
					    ))))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Loads a `BrightnessGrid` with the specified dimensions from the provided data.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Panics
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// When the provided `data_length` is not sufficient for the `height` and `width`
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # 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_brightness_grid_dealloc`.
 | 
				
			||||||
 | 
					#[no_mangle]
 | 
				
			||||||
 | 
					pub unsafe extern "C" fn sp_brightness_grid_load(
 | 
				
			||||||
 | 
					    width: usize,
 | 
				
			||||||
 | 
					    height: usize,
 | 
				
			||||||
 | 
					    data: *const u8,
 | 
				
			||||||
 | 
					    data_length: usize,
 | 
				
			||||||
 | 
					) -> *mut CBrightnessGrid {
 | 
				
			||||||
 | 
					    let data = std::slice::from_raw_parts(data, data_length);
 | 
				
			||||||
 | 
					    let grid = PrimitiveGrid::load(width, height, data);
 | 
				
			||||||
 | 
					    let grid =
 | 
				
			||||||
 | 
					        BrightnessGrid::try_from(grid).expect("invalid brightness value");
 | 
				
			||||||
 | 
					    Box::into_raw(Box::new(CBrightnessGrid(grid)))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Clones a `BrightnessGrid`.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Safety
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 | 
					/// - `this` is not written to concurrently
 | 
				
			||||||
 | 
					/// - the returned instance is freed in some way, either by using a consuming function or
 | 
				
			||||||
 | 
					///   by explicitly calling `sp_brightness_grid_dealloc`.
 | 
				
			||||||
 | 
					#[no_mangle]
 | 
				
			||||||
 | 
					pub unsafe extern "C" fn sp_brightness_grid_clone(
 | 
				
			||||||
 | 
					    this: *const CBrightnessGrid,
 | 
				
			||||||
 | 
					) -> *mut CBrightnessGrid {
 | 
				
			||||||
 | 
					    Box::into_raw(Box::new((*this).clone()))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Deallocates a `BrightnessGrid`.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Safety
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 | 
					/// - `this` is not used concurrently or after this call
 | 
				
			||||||
 | 
					/// - `this` was not passed to another consuming function, e.g. to create a `Command`
 | 
				
			||||||
 | 
					#[no_mangle]
 | 
				
			||||||
 | 
					pub unsafe extern "C" fn sp_brightness_grid_dealloc(
 | 
				
			||||||
 | 
					    this: *mut CBrightnessGrid,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    _ = Box::from_raw(this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Gets the current value at the specified position.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Arguments
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// * `this`: 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:
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 | 
					/// - `this` is not written to concurrently
 | 
				
			||||||
 | 
					#[no_mangle]
 | 
				
			||||||
 | 
					pub unsafe extern "C" fn sp_brightness_grid_get(
 | 
				
			||||||
 | 
					    this: *const CBrightnessGrid,
 | 
				
			||||||
 | 
					    x: usize,
 | 
				
			||||||
 | 
					    y: usize,
 | 
				
			||||||
 | 
					) -> u8 {
 | 
				
			||||||
 | 
					    (*this).0.get(x, y).into()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Sets the value of the specified position in the `BrightnessGrid`.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Arguments
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// * `this`: 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:
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// - `this` points to a valid `BitVec`
 | 
				
			||||||
 | 
					/// - `this` is not written to or read from concurrently
 | 
				
			||||||
 | 
					#[no_mangle]
 | 
				
			||||||
 | 
					pub unsafe extern "C" fn sp_brightness_grid_set(
 | 
				
			||||||
 | 
					    this: *mut CBrightnessGrid,
 | 
				
			||||||
 | 
					    x: usize,
 | 
				
			||||||
 | 
					    y: usize,
 | 
				
			||||||
 | 
					    value: u8,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    let brightness =
 | 
				
			||||||
 | 
					        Brightness::try_from(value).expect("invalid brightness value");
 | 
				
			||||||
 | 
					    (*this).0.set(x, y, brightness);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Sets the value of all cells in the `BrightnessGrid`.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Arguments
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// * `this`: instance to write to
 | 
				
			||||||
 | 
					/// * `value`: the value to set all cells to
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Safety
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 | 
					/// - `this` is not written to or read from concurrently
 | 
				
			||||||
 | 
					#[no_mangle]
 | 
				
			||||||
 | 
					pub unsafe extern "C" fn sp_brightness_grid_fill(
 | 
				
			||||||
 | 
					    this: *mut CBrightnessGrid,
 | 
				
			||||||
 | 
					    value: u8,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    let brightness =
 | 
				
			||||||
 | 
					        Brightness::try_from(value).expect("invalid brightness value");
 | 
				
			||||||
 | 
					    (*this).0.fill(brightness);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Gets the width of the `BrightnessGrid` instance.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Arguments
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// * `this`: instance to read from
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Safety
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 | 
					#[no_mangle]
 | 
				
			||||||
 | 
					pub unsafe extern "C" fn sp_brightness_grid_width(
 | 
				
			||||||
 | 
					    this: *const CBrightnessGrid,
 | 
				
			||||||
 | 
					) -> usize {
 | 
				
			||||||
 | 
					    (*this).0.width()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Gets the height of the `BrightnessGrid` instance.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Arguments
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// * `this`: instance to read from
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Safety
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 | 
					#[no_mangle]
 | 
				
			||||||
 | 
					pub unsafe extern "C" fn sp_brightness_grid_height(
 | 
				
			||||||
 | 
					    this: *const CBrightnessGrid,
 | 
				
			||||||
 | 
					) -> usize {
 | 
				
			||||||
 | 
					    (*this).0.height()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Gets an unsafe reference to the data of the `BrightnessGrid` instance.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ## Safety
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// - `this` points to a valid `BrightnessGrid`
 | 
				
			||||||
 | 
					/// - the returned memory range is never accessed after the passed `BrightnessGrid` has been freed
 | 
				
			||||||
 | 
					/// - the returned memory range is never accessed concurrently, either via the `BrightnessGrid` or directly
 | 
				
			||||||
 | 
					#[no_mangle]
 | 
				
			||||||
 | 
					pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref(
 | 
				
			||||||
 | 
					    this: *mut CBrightnessGrid,
 | 
				
			||||||
 | 
					) -> CByteSlice {
 | 
				
			||||||
 | 
					    assert_eq!(std::mem::size_of::<Brightness>(), 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let data = (*this).0.data_ref_mut();
 | 
				
			||||||
 | 
					    let data: &mut [u8] = transmute(data);
 | 
				
			||||||
 | 
					    CByteSlice {
 | 
				
			||||||
 | 
					        start: data.as_mut_ptr_range().start,
 | 
				
			||||||
 | 
					        length: data.len(),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -5,11 +5,12 @@
 | 
				
			||||||
use std::ptr::null_mut;
 | 
					use std::ptr::null_mut;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use servicepoint::{
 | 
					use servicepoint::{
 | 
				
			||||||
    Brightness, ByteGrid, Command, CompressionCode, Offset, Origin, Packet,
 | 
					    Brightness, Command, CompressionCode, Offset, Origin, Packet, PixelGrid,
 | 
				
			||||||
    PixelGrid,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::bit_vec::CBitVec;
 | 
					use crate::bit_vec::CBitVec;
 | 
				
			||||||
 | 
					use crate::brightness_grid::CBrightnessGrid;
 | 
				
			||||||
 | 
					use crate::cp437_grid::CCp437Grid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Tries to turn a `Packet` into a `Command`. The packet is deallocated in the process.
 | 
					/// Tries to turn a `Packet` into a `Command`. The packet is deallocated in the process.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -91,7 +92,12 @@ pub unsafe extern "C" fn sp_command_fade_out() -> *mut Command {
 | 
				
			||||||
    Box::into_raw(Box::new(Command::FadeOut))
 | 
					    Box::into_raw(Box::new(Command::FadeOut))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Allocates a new `Command::Brightness` instance.
 | 
					/// Allocates a new `Command::Brightness` instance for setting the brightness of all tiles to the
 | 
				
			||||||
 | 
					/// same value.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Panics
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// - When the provided brightness value is out of range (0-11).
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Safety
 | 
					/// # Safety
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -100,9 +106,9 @@ pub unsafe extern "C" fn sp_command_fade_out() -> *mut Command {
 | 
				
			||||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
 | 
					/// - the returned `Command` instance is freed in some way, either by using a consuming function or
 | 
				
			||||||
///   by explicitly calling `sp_command_dealloc`.
 | 
					///   by explicitly calling `sp_command_dealloc`.
 | 
				
			||||||
#[no_mangle]
 | 
					#[no_mangle]
 | 
				
			||||||
pub unsafe extern "C" fn sp_command_brightness(
 | 
					pub unsafe extern "C" fn sp_command_brightness(brightness: u8) -> *mut Command {
 | 
				
			||||||
    brightness: Brightness,
 | 
					    let brightness =
 | 
				
			||||||
) -> *mut Command {
 | 
					        Brightness::try_from(brightness).expect("invalid brightness");
 | 
				
			||||||
    Box::into_raw(Box::new(Command::Brightness(brightness)))
 | 
					    Box::into_raw(Box::new(Command::Brightness(brightness)))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,10 +127,13 @@ pub unsafe extern "C" fn sp_command_brightness(
 | 
				
			||||||
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,
 | 
				
			||||||
    byte_grid: *mut ByteGrid,
 | 
					    byte_grid: *mut CBrightnessGrid,
 | 
				
			||||||
) -> *mut Command {
 | 
					) -> *mut Command {
 | 
				
			||||||
    let byte_grid = *Box::from_raw(byte_grid);
 | 
					    let byte_grid = *Box::from_raw(byte_grid);
 | 
				
			||||||
    Box::into_raw(Box::new(Command::CharBrightness(Origin(x, y), byte_grid)))
 | 
					    Box::into_raw(Box::new(Command::CharBrightness(
 | 
				
			||||||
 | 
					        Origin::new(x, y),
 | 
				
			||||||
 | 
					        byte_grid.0,
 | 
				
			||||||
 | 
					    )))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Allocates a new `Command::BitmapLinear` instance.
 | 
					/// Allocates a new `Command::BitmapLinear` instance.
 | 
				
			||||||
| 
						 | 
					@ -246,10 +255,10 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
 | 
				
			||||||
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,
 | 
				
			||||||
    byte_grid: *mut ByteGrid,
 | 
					    byte_grid: *mut CCp437Grid,
 | 
				
			||||||
) -> *mut Command {
 | 
					) -> *mut Command {
 | 
				
			||||||
    let byte_grid = *Box::from_raw(byte_grid);
 | 
					    let byte_grid = *Box::from_raw(byte_grid);
 | 
				
			||||||
    Box::into_raw(Box::new(Command::Cp437Data(Origin(x, y), byte_grid)))
 | 
					    Box::into_raw(Box::new(Command::Cp437Data(Origin::new(x, y), byte_grid.0)))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Allocates a new `Command::BitmapLinearWin` instance.
 | 
					/// Allocates a new `Command::BitmapLinearWin` instance.
 | 
				
			||||||
| 
						 | 
					@ -273,7 +282,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_win(
 | 
				
			||||||
) -> *mut Command {
 | 
					) -> *mut Command {
 | 
				
			||||||
    let byte_grid = *Box::from_raw(pixel_grid);
 | 
					    let byte_grid = *Box::from_raw(pixel_grid);
 | 
				
			||||||
    Box::into_raw(Box::new(Command::BitmapLinearWin(
 | 
					    Box::into_raw(Box::new(Command::BitmapLinearWin(
 | 
				
			||||||
        Origin(x, y),
 | 
					        Origin::new(x, y),
 | 
				
			||||||
        byte_grid,
 | 
					        byte_grid,
 | 
				
			||||||
        compression_code,
 | 
					        compression_code,
 | 
				
			||||||
    )))
 | 
					    )))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,30 +1,36 @@
 | 
				
			||||||
//! C functions for interacting with `ByteGrid`s
 | 
					//! C functions for interacting with `Cp437Grid`s
 | 
				
			||||||
//!
 | 
					//!
 | 
				
			||||||
//! prefix `sp_byte_grid_`
 | 
					//! prefix `sp_cp437_grid_`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use servicepoint::{ByteGrid, DataRef, Grid};
 | 
					use servicepoint::{Cp437Grid, DataRef, Grid};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::c_slice::CByteSlice;
 | 
					use crate::c_slice::CByteSlice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Creates a new `ByteGrid` with the specified dimensions.
 | 
					/// A C-wrapper for grid containing codepage 437 characters.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// returns: `ByteGrid` initialized to 0.
 | 
					/// The encoding is currently not enforced.
 | 
				
			||||||
 | 
					#[derive(Clone)]
 | 
				
			||||||
 | 
					pub struct CCp437Grid(pub(crate) Cp437Grid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Creates a new `Cp437Grid` with the specified dimensions.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// returns: `Cp437Grid` initialized to 0.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # 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_byte_grid_dealloc`.
 | 
					///   by explicitly calling `sp_cp437_grid_dealloc`.
 | 
				
			||||||
#[no_mangle]
 | 
					#[no_mangle]
 | 
				
			||||||
pub unsafe extern "C" fn sp_byte_grid_new(
 | 
					pub unsafe extern "C" fn sp_cp437_grid_new(
 | 
				
			||||||
    width: usize,
 | 
					    width: usize,
 | 
				
			||||||
    height: usize,
 | 
					    height: usize,
 | 
				
			||||||
) -> *mut ByteGrid {
 | 
					) -> *mut CCp437Grid {
 | 
				
			||||||
    Box::into_raw(Box::new(ByteGrid::new(width, height)))
 | 
					    Box::into_raw(Box::new(CCp437Grid(Cp437Grid::new(width, height))))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Loads a `ByteGrid` with the specified dimensions from the provided data.
 | 
					/// Loads a `Cp437Grid` with the specified dimensions from the provided data.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Panics
 | 
					/// # Panics
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -37,46 +43,46 @@ pub unsafe extern "C" fn sp_byte_grid_new(
 | 
				
			||||||
/// - `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_byte_grid_dealloc`.
 | 
					///   by explicitly calling `sp_cp437_grid_dealloc`.
 | 
				
			||||||
#[no_mangle]
 | 
					#[no_mangle]
 | 
				
			||||||
pub unsafe extern "C" fn sp_byte_grid_load(
 | 
					pub unsafe extern "C" fn sp_cp437_grid_load(
 | 
				
			||||||
    width: usize,
 | 
					    width: usize,
 | 
				
			||||||
    height: usize,
 | 
					    height: usize,
 | 
				
			||||||
    data: *const u8,
 | 
					    data: *const u8,
 | 
				
			||||||
    data_length: usize,
 | 
					    data_length: usize,
 | 
				
			||||||
) -> *mut ByteGrid {
 | 
					) -> *mut CCp437Grid {
 | 
				
			||||||
    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(ByteGrid::load(width, height, data)))
 | 
					    Box::into_raw(Box::new(CCp437Grid(Cp437Grid::load(width, height, data))))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Clones a `ByteGrid`.
 | 
					/// Clones a `Cp437Grid`.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Safety
 | 
					/// # Safety
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// The caller has to make sure that:
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// - `this` points to a valid `ByteGrid`
 | 
					/// - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
/// - `this` is not written to concurrently
 | 
					/// - `this` 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_byte_grid_dealloc`.
 | 
					///   by explicitly calling `sp_cp437_grid_dealloc`.
 | 
				
			||||||
#[no_mangle]
 | 
					#[no_mangle]
 | 
				
			||||||
pub unsafe extern "C" fn sp_byte_grid_clone(
 | 
					pub unsafe extern "C" fn sp_cp437_grid_clone(
 | 
				
			||||||
    this: *const ByteGrid,
 | 
					    this: *const CCp437Grid,
 | 
				
			||||||
) -> *mut ByteGrid {
 | 
					) -> *mut CCp437Grid {
 | 
				
			||||||
    Box::into_raw(Box::new((*this).clone()))
 | 
					    Box::into_raw(Box::new((*this).clone()))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Deallocates a `ByteGrid`.
 | 
					/// Deallocates a `Cp437Grid`.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Safety
 | 
					/// # Safety
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// The caller has to make sure that:
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// - `this` points to a valid `ByteGrid`
 | 
					/// - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
/// - `this` is not used concurrently or after this call
 | 
					/// - `this` is not used concurrently or after this call
 | 
				
			||||||
/// - `this` was not passed to another consuming function, e.g. to create a `Command`
 | 
					/// - `this` was not passed to another consuming function, e.g. to create a `Command`
 | 
				
			||||||
#[no_mangle]
 | 
					#[no_mangle]
 | 
				
			||||||
pub unsafe extern "C" fn sp_byte_grid_dealloc(this: *mut ByteGrid) {
 | 
					pub unsafe extern "C" fn sp_cp437_grid_dealloc(this: *mut CCp437Grid) {
 | 
				
			||||||
    _ = Box::from_raw(this);
 | 
					    _ = Box::from_raw(this);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -95,18 +101,18 @@ pub unsafe extern "C" fn sp_byte_grid_dealloc(this: *mut ByteGrid) {
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// The caller has to make sure that:
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// - `this` points to a valid `ByteGrid`
 | 
					/// - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
/// - `this` is not written to concurrently
 | 
					/// - `this` is not written to concurrently
 | 
				
			||||||
#[no_mangle]
 | 
					#[no_mangle]
 | 
				
			||||||
pub unsafe extern "C" fn sp_byte_grid_get(
 | 
					pub unsafe extern "C" fn sp_cp437_grid_get(
 | 
				
			||||||
    this: *const ByteGrid,
 | 
					    this: *const CCp437Grid,
 | 
				
			||||||
    x: usize,
 | 
					    x: usize,
 | 
				
			||||||
    y: usize,
 | 
					    y: usize,
 | 
				
			||||||
) -> u8 {
 | 
					) -> u8 {
 | 
				
			||||||
    (*this).get(x, y)
 | 
					    (*this).0.get(x, y)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Sets the value of the specified position in the `ByteGrid`.
 | 
					/// Sets the value of the specified position in the `Cp437Grid`.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Arguments
 | 
					/// # Arguments
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -127,16 +133,16 @@ pub unsafe extern "C" fn sp_byte_grid_get(
 | 
				
			||||||
/// - `this` points to a valid `BitVec`
 | 
					/// - `this` points to a valid `BitVec`
 | 
				
			||||||
/// - `this` is not written to or read from concurrently
 | 
					/// - `this` is not written to or read from concurrently
 | 
				
			||||||
#[no_mangle]
 | 
					#[no_mangle]
 | 
				
			||||||
pub unsafe extern "C" fn sp_byte_grid_set(
 | 
					pub unsafe extern "C" fn sp_cp437_grid_set(
 | 
				
			||||||
    this: *mut ByteGrid,
 | 
					    this: *mut CCp437Grid,
 | 
				
			||||||
    x: usize,
 | 
					    x: usize,
 | 
				
			||||||
    y: usize,
 | 
					    y: usize,
 | 
				
			||||||
    value: u8,
 | 
					    value: u8,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    (*this).set(x, y, value);
 | 
					    (*this).0.set(x, y, value);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Sets the value of all cells in the `ByteGrid`.
 | 
					/// Sets the value of all cells in the `Cp437Grid`.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Arguments
 | 
					/// # Arguments
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -147,14 +153,14 @@ pub unsafe extern "C" fn sp_byte_grid_set(
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// The caller has to make sure that:
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// - `this` points to a valid `ByteGrid`
 | 
					/// - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
/// - `this` is not written to or read from concurrently
 | 
					/// - `this` is not written to or read from concurrently
 | 
				
			||||||
#[no_mangle]
 | 
					#[no_mangle]
 | 
				
			||||||
pub unsafe extern "C" fn sp_byte_grid_fill(this: *mut ByteGrid, value: u8) {
 | 
					pub unsafe extern "C" fn sp_cp437_grid_fill(this: *mut CCp437Grid, value: u8) {
 | 
				
			||||||
    (*this).fill(value);
 | 
					    (*this).0.fill(value);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gets the width of the `ByteGrid` instance.
 | 
					/// Gets the width of the `Cp437Grid` instance.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Arguments
 | 
					/// # Arguments
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -164,13 +170,13 @@ pub unsafe extern "C" fn sp_byte_grid_fill(this: *mut ByteGrid, value: u8) {
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// The caller has to make sure that:
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// - `this` points to a valid `ByteGrid`
 | 
					/// - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
#[no_mangle]
 | 
					#[no_mangle]
 | 
				
			||||||
pub unsafe extern "C" fn sp_byte_grid_width(this: *const ByteGrid) -> usize {
 | 
					pub unsafe extern "C" fn sp_cp437_grid_width(this: *const CCp437Grid) -> usize {
 | 
				
			||||||
    (*this).width()
 | 
					    (*this).0.width()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gets the height of the `ByteGrid` instance.
 | 
					/// Gets the height of the `Cp437Grid` instance.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Arguments
 | 
					/// # Arguments
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -180,26 +186,28 @@ pub unsafe extern "C" fn sp_byte_grid_width(this: *const ByteGrid) -> usize {
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// The caller has to make sure that:
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// - `this` points to a valid `ByteGrid`
 | 
					/// - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
#[no_mangle]
 | 
					#[no_mangle]
 | 
				
			||||||
pub unsafe extern "C" fn sp_byte_grid_height(this: *const ByteGrid) -> usize {
 | 
					pub unsafe extern "C" fn sp_cp437_grid_height(
 | 
				
			||||||
    (*this).height()
 | 
					    this: *const CCp437Grid,
 | 
				
			||||||
 | 
					) -> usize {
 | 
				
			||||||
 | 
					    (*this).0.height()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gets an unsafe reference to the data of the `ByteGrid` instance.
 | 
					/// Gets an unsafe reference to the data of the `Cp437Grid` instance.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// ## Safety
 | 
					/// ## Safety
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// The caller has to make sure that:
 | 
					/// The caller has to make sure that:
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// - `this` points to a valid `ByteGrid`
 | 
					/// - `this` points to a valid `Cp437Grid`
 | 
				
			||||||
/// - the returned memory range is never accessed after the passed `ByteGrid` has been freed
 | 
					/// - the returned memory range is never accessed after the passed `Cp437Grid` has been freed
 | 
				
			||||||
/// - the returned memory range is never accessed concurrently, either via the `ByteGrid` or directly
 | 
					/// - the returned memory range is never accessed concurrently, either via the `Cp437Grid` or directly
 | 
				
			||||||
#[no_mangle]
 | 
					#[no_mangle]
 | 
				
			||||||
pub unsafe extern "C" fn sp_byte_grid_unsafe_data_ref(
 | 
					pub unsafe extern "C" fn sp_cp437_grid_unsafe_data_ref(
 | 
				
			||||||
    this: *mut ByteGrid,
 | 
					    this: *mut CCp437Grid,
 | 
				
			||||||
) -> CByteSlice {
 | 
					) -> CByteSlice {
 | 
				
			||||||
    let data = (*this).data_ref_mut();
 | 
					    let data = (*this).0.data_ref_mut();
 | 
				
			||||||
    CByteSlice {
 | 
					    CByteSlice {
 | 
				
			||||||
        start: data.as_mut_ptr_range().start,
 | 
					        start: data.as_mut_ptr_range().start,
 | 
				
			||||||
        length: data.len(),
 | 
					        length: data.len(),
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@ pub use crate::c_slice::CByteSlice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod bit_vec;
 | 
					pub mod bit_vec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod byte_grid;
 | 
					pub mod brightness_grid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod command;
 | 
					pub mod command;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,9 @@ pub mod packet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod pixel_grid;
 | 
					pub mod pixel_grid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod c_slice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod cp437_grid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The minimum time needed for the display to refresh the screen in ms.
 | 
					/// The minimum time needed for the display to refresh the screen in ms.
 | 
				
			||||||
pub const FRAME_PACING_MS: u32 = servicepoint::FRAME_PACING.as_millis() as u32;
 | 
					pub const FRAME_PACING_MS: u32 = servicepoint::FRAME_PACING.as_millis() as u32;
 | 
				
			||||||
 | 
					 | 
				
			||||||
pub mod c_slice;
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,8 +13,8 @@ test = false
 | 
				
			||||||
csbindgen = "1.8.0"
 | 
					csbindgen = "1.8.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
servicepoint_binding_c = { version = "0.6.0", path = "../servicepoint_binding_c" }
 | 
					servicepoint_binding_c = { version = "0.7.0", path = "../servicepoint_binding_c" }
 | 
				
			||||||
servicepoint = { version = "0.6.0", path = "../servicepoint" }
 | 
					servicepoint = { version = "0.7.0", path = "../servicepoint" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[lints]
 | 
					[lints]
 | 
				
			||||||
workspace = true
 | 
					workspace = true
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,45 +61,85 @@ namespace ServicePoint.BindGen
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern CByteSlice sp_bit_vec_unsafe_data_ref(CBitVec* @this);
 | 
					        public static extern CByteSlice sp_bit_vec_unsafe_data_ref(CBitVec* @this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Creates a new `ByteGrid` with the specified dimensions.  returns: `ByteGrid` initialized to 0.  # 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_byte_grid_dealloc`.</summary>
 | 
					        /// <summary>Creates a new `BrightnessGrid` with the specified dimensions.  returns: `BrightnessGrid` initialized to 0.  # 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_brightness_grid_dealloc`.</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_byte_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_brightness_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern ByteGrid* sp_byte_grid_new(nuint width, nuint height);
 | 
					        public static extern CBrightnessGrid* sp_brightness_grid_new(nuint width, nuint height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Loads a `ByteGrid` with the specified dimensions from the provided data.  # Panics  When the provided `data_length` is not sufficient for the `height` and `width`  # 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_byte_grid_dealloc`.</summary>
 | 
					        /// <summary>Loads a `BrightnessGrid` with the specified dimensions from the provided data.  # Panics  When the provided `data_length` is not sufficient for the `height` and `width`  # 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_brightness_grid_dealloc`.</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_byte_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_brightness_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern ByteGrid* sp_byte_grid_load(nuint width, nuint height, byte* data, nuint data_length);
 | 
					        public static extern CBrightnessGrid* sp_brightness_grid_load(nuint width, nuint height, byte* data, nuint data_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Clones a `ByteGrid`.  # Safety  The caller has to make sure that:  - `this` points to a valid `ByteGrid` - `this` is not written to concurrently - the returned instance is freed in some way, either by using a consuming function or by explicitly calling `sp_byte_grid_dealloc`.</summary>
 | 
					        /// <summary>Clones a `BrightnessGrid`.  # Safety  The caller has to make sure that:  - `this` points to a valid `BrightnessGrid` - `this` is not written to concurrently - the returned instance is freed in some way, either by using a consuming function or by explicitly calling `sp_brightness_grid_dealloc`.</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_byte_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_brightness_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern ByteGrid* sp_byte_grid_clone(ByteGrid* @this);
 | 
					        public static extern CBrightnessGrid* sp_brightness_grid_clone(CBrightnessGrid* @this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Deallocates a `ByteGrid`.  # Safety  The caller has to make sure that:  - `this` points to a valid `ByteGrid` - `this` is not used concurrently or after this call - `this` was not passed to another consuming function, e.g. to create a `Command`</summary>
 | 
					        /// <summary>Deallocates a `BrightnessGrid`.  # Safety  The caller has to make sure that:  - `this` points to a valid `BrightnessGrid` - `this` is not used concurrently or after this call - `this` was not passed to another consuming function, e.g. to create a `Command`</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_byte_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_brightness_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern void sp_byte_grid_dealloc(ByteGrid* @this);
 | 
					        public static extern void sp_brightness_grid_dealloc(CBrightnessGrid* @this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Gets the current value at the specified position.  # Arguments  * `this`: 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:  - `this` points to a valid `ByteGrid` - `this` is not written to concurrently</summary>
 | 
					        /// <summary>Gets the current value at the specified position.  # Arguments  * `this`: 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:  - `this` points to a valid `BrightnessGrid` - `this` is not written to concurrently</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_byte_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_brightness_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern byte sp_byte_grid_get(ByteGrid* @this, nuint x, nuint y);
 | 
					        public static extern byte sp_brightness_grid_get(CBrightnessGrid* @this, nuint x, nuint y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Sets the value of the specified position in the `ByteGrid`.  # Arguments  * `this`: 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:  - `this` points to a valid `BitVec` - `this` is not written to or read from concurrently</summary>
 | 
					        /// <summary>Sets the value of the specified position in the `BrightnessGrid`.  # Arguments  * `this`: 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:  - `this` points to a valid `BitVec` - `this` is not written to or read from concurrently</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_byte_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_brightness_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern void sp_byte_grid_set(ByteGrid* @this, nuint x, nuint y, byte value);
 | 
					        public static extern void sp_brightness_grid_set(CBrightnessGrid* @this, nuint x, nuint y, byte value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Sets the value of all cells in the `ByteGrid`.  # Arguments  * `this`: instance to write to * `value`: the value to set all cells to  # Safety  The caller has to make sure that:  - `this` points to a valid `ByteGrid` - `this` is not written to or read from concurrently</summary>
 | 
					        /// <summary>Sets the value of all cells in the `BrightnessGrid`.  # Arguments  * `this`: instance to write to * `value`: the value to set all cells to  # Safety  The caller has to make sure that:  - `this` points to a valid `BrightnessGrid` - `this` is not written to or read from concurrently</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_byte_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_brightness_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern void sp_byte_grid_fill(ByteGrid* @this, byte value);
 | 
					        public static extern void sp_brightness_grid_fill(CBrightnessGrid* @this, byte value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Gets the width of the `ByteGrid` instance.  # Arguments  * `this`: instance to read from  # Safety  The caller has to make sure that:  - `this` points to a valid `ByteGrid`</summary>
 | 
					        /// <summary>Gets the width of the `BrightnessGrid` instance.  # Arguments  * `this`: instance to read from  # Safety  The caller has to make sure that:  - `this` points to a valid `BrightnessGrid`</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_byte_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_brightness_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern nuint sp_byte_grid_width(ByteGrid* @this);
 | 
					        public static extern nuint sp_brightness_grid_width(CBrightnessGrid* @this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Gets the height of the `ByteGrid` instance.  # Arguments  * `this`: instance to read from  # Safety  The caller has to make sure that:  - `this` points to a valid `ByteGrid`</summary>
 | 
					        /// <summary>Gets the height of the `BrightnessGrid` instance.  # Arguments  * `this`: instance to read from  # Safety  The caller has to make sure that:  - `this` points to a valid `BrightnessGrid`</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_byte_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_brightness_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern nuint sp_byte_grid_height(ByteGrid* @this);
 | 
					        public static extern nuint sp_brightness_grid_height(CBrightnessGrid* @this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Gets an unsafe reference to the data of the `ByteGrid` instance.  ## Safety  The caller has to make sure that:  - `this` points to a valid `ByteGrid` - the returned memory range is never accessed after the passed `ByteGrid` has been freed - the returned memory range is never accessed concurrently, either via the `ByteGrid` or directly</summary>
 | 
					        /// <summary>Gets an unsafe reference to the data of the `BrightnessGrid` instance.  ## Safety  The caller has to make sure that:  - `this` points to a valid `BrightnessGrid` - the returned memory range is never accessed after the passed `BrightnessGrid` has been freed - the returned memory range is never accessed concurrently, either via the `BrightnessGrid` or directly</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_byte_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_brightness_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern CByteSlice sp_byte_grid_unsafe_data_ref(ByteGrid* @this);
 | 
					        public static extern CByteSlice sp_brightness_grid_unsafe_data_ref(CBrightnessGrid* @this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>Creates a new `Cp437Grid` with the specified dimensions.  returns: `Cp437Grid` initialized to 0.  # 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_cp437_grid_dealloc`.</summary>
 | 
				
			||||||
 | 
					        [DllImport(__DllName, EntryPoint = "sp_cp437_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
 | 
					        public static extern CCp437Grid* sp_cp437_grid_new(nuint width, nuint height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>Loads a `Cp437Grid` with the specified dimensions from the provided data.  # Panics  When the provided `data_length` is not sufficient for the `height` and `width`  # 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_cp437_grid_dealloc`.</summary>
 | 
				
			||||||
 | 
					        [DllImport(__DllName, EntryPoint = "sp_cp437_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
 | 
					        public static extern CCp437Grid* sp_cp437_grid_load(nuint width, nuint height, byte* data, nuint data_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>Clones a `Cp437Grid`.  # Safety  The caller has to make sure that:  - `this` points to a valid `Cp437Grid` - `this` is not written to concurrently - the returned instance is freed in some way, either by using a consuming function or by explicitly calling `sp_cp437_grid_dealloc`.</summary>
 | 
				
			||||||
 | 
					        [DllImport(__DllName, EntryPoint = "sp_cp437_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
 | 
					        public static extern CCp437Grid* sp_cp437_grid_clone(CCp437Grid* @this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>Deallocates a `Cp437Grid`.  # Safety  The caller has to make sure that:  - `this` points to a valid `Cp437Grid` - `this` is not used concurrently or after this call - `this` was not passed to another consuming function, e.g. to create a `Command`</summary>
 | 
				
			||||||
 | 
					        [DllImport(__DllName, EntryPoint = "sp_cp437_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
 | 
					        public static extern void sp_cp437_grid_dealloc(CCp437Grid* @this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>Gets the current value at the specified position.  # Arguments  * `this`: 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:  - `this` points to a valid `Cp437Grid` - `this` is not written to concurrently</summary>
 | 
				
			||||||
 | 
					        [DllImport(__DllName, EntryPoint = "sp_cp437_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
 | 
					        public static extern byte sp_cp437_grid_get(CCp437Grid* @this, nuint x, nuint y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>Sets the value of the specified position in the `Cp437Grid`.  # Arguments  * `this`: 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:  - `this` points to a valid `BitVec` - `this` is not written to or read from concurrently</summary>
 | 
				
			||||||
 | 
					        [DllImport(__DllName, EntryPoint = "sp_cp437_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
 | 
					        public static extern void sp_cp437_grid_set(CCp437Grid* @this, nuint x, nuint y, byte value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>Sets the value of all cells in the `Cp437Grid`.  # Arguments  * `this`: instance to write to * `value`: the value to set all cells to  # Safety  The caller has to make sure that:  - `this` points to a valid `Cp437Grid` - `this` is not written to or read from concurrently</summary>
 | 
				
			||||||
 | 
					        [DllImport(__DllName, EntryPoint = "sp_cp437_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
 | 
					        public static extern void sp_cp437_grid_fill(CCp437Grid* @this, byte value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>Gets the width of the `Cp437Grid` instance.  # Arguments  * `this`: instance to read from  # Safety  The caller has to make sure that:  - `this` points to a valid `Cp437Grid`</summary>
 | 
				
			||||||
 | 
					        [DllImport(__DllName, EntryPoint = "sp_cp437_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
 | 
					        public static extern nuint sp_cp437_grid_width(CCp437Grid* @this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>Gets the height of the `Cp437Grid` instance.  # Arguments  * `this`: instance to read from  # Safety  The caller has to make sure that:  - `this` points to a valid `Cp437Grid`</summary>
 | 
				
			||||||
 | 
					        [DllImport(__DllName, EntryPoint = "sp_cp437_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
 | 
					        public static extern nuint sp_cp437_grid_height(CCp437Grid* @this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>Gets an unsafe reference to the data of the `Cp437Grid` instance.  ## Safety  The caller has to make sure that:  - `this` points to a valid `Cp437Grid` - the returned memory range is never accessed after the passed `Cp437Grid` has been freed - the returned memory range is never accessed concurrently, either via the `Cp437Grid` or directly</summary>
 | 
				
			||||||
 | 
					        [DllImport(__DllName, EntryPoint = "sp_cp437_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
 | 
					        public static extern CByteSlice sp_cp437_grid_unsafe_data_ref(CCp437Grid* @this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Tries to turn a `Packet` into a `Command`. The packet is deallocated in the process.  Returns: pointer to new `Command` instance or NULL  # Safety  The caller has to make sure that:  - `packet` points to a valid instance of `Packet` - `packet` is not used concurrently or after this call - the result is checked for NULL - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
					        /// <summary>Tries to turn a `Packet` into a `Command`. The packet is deallocated in the process.  Returns: pointer to new `Command` instance or NULL  # Safety  The caller has to make sure that:  - `packet` points to a valid instance of `Packet` - `packet` is not used concurrently or after this call - the result is checked for NULL - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
| 
						 | 
					@ -121,13 +161,13 @@ namespace ServicePoint.BindGen
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern Command* sp_command_fade_out();
 | 
					        public static extern Command* sp_command_fade_out();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Allocates a new `Command::Brightness` instance.  # Safety  The caller has to make sure that:  - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
					        /// <summary>Allocates a new `Command::Brightness` instance for setting the brightness of all tiles to the same value.  # Panics  - When the provided brightness value is out of range (0-11).  # Safety  The caller has to make sure that:  - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern Command* sp_command_brightness(byte brightness);
 | 
					        public static extern Command* sp_command_brightness(byte brightness);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Allocates a new `Command::CharBrightness` instance. The passed `ByteGrid` gets consumed.  # Safety  The caller has to make sure that:  - `byte_grid` points to a valid instance of `ByteGrid` - `byte_grid` is not used concurrently or after this call - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
					        /// <summary>Allocates a new `Command::CharBrightness` instance. The passed `ByteGrid` gets consumed.  # Safety  The caller has to make sure that:  - `byte_grid` points to a valid instance of `ByteGrid` - `byte_grid` is not used concurrently or after this call - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_command_char_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_command_char_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern Command* sp_command_char_brightness(nuint x, nuint y, ByteGrid* byte_grid);
 | 
					        public static extern Command* sp_command_char_brightness(nuint x, nuint y, CBrightnessGrid* byte_grid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Allocates a new `Command::BitmapLinear` instance. The passed `BitVec` gets consumed.  # Safety  The caller has to make sure that:  - `bit_vec` points to a valid instance of `BitVec` - `bit_vec` is not used concurrently or after this call - `compression` matches one of the allowed enum values - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
					        /// <summary>Allocates a new `Command::BitmapLinear` instance. The passed `BitVec` gets consumed.  # Safety  The caller has to make sure that:  - `bit_vec` points to a valid instance of `BitVec` - `bit_vec` is not used concurrently or after this call - `compression` matches one of the allowed enum values - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
| 
						 | 
					@ -147,7 +187,7 @@ namespace ServicePoint.BindGen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Allocates a new `Command::Cp437Data` instance. The passed `ByteGrid` gets consumed.  # Safety  The caller has to make sure that:  - `byte_grid` points to a valid instance of `ByteGrid` - `byte_grid` is not used concurrently or after this call - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
					        /// <summary>Allocates a new `Command::Cp437Data` instance. The passed `ByteGrid` gets consumed.  # Safety  The caller has to make sure that:  - `byte_grid` points to a valid instance of `ByteGrid` - `byte_grid` is not used concurrently or after this call - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_command_cp437_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_command_cp437_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
        public static extern Command* sp_command_cp437_data(nuint x, nuint y, ByteGrid* byte_grid);
 | 
					        public static extern Command* sp_command_cp437_data(nuint x, nuint y, CCp437Grid* byte_grid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>Allocates a new `Command::BitmapLinearWin` instance. The passed `PixelGrid` gets consumed.  # Safety  The caller has to make sure that:  - `pixel_grid` points to a valid instance of `PixelGrid` - `pixel_grid` is not used concurrently or after this call - `compression` matches one of the allowed enum values - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
					        /// <summary>Allocates a new `Command::BitmapLinearWin` instance. The passed `PixelGrid` gets consumed.  # Safety  The caller has to make sure that:  - `pixel_grid` points to a valid instance of `PixelGrid` - `pixel_grid` is not used concurrently or after this call - `compression` matches one of the allowed enum values - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
 | 
				
			||||||
        [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
					        [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
 | 
				
			||||||
| 
						 | 
					@ -231,6 +271,16 @@ namespace ServicePoint.BindGen
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [StructLayout(LayoutKind.Sequential)]
 | 
				
			||||||
 | 
					    public unsafe partial struct CBrightnessGrid
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [StructLayout(LayoutKind.Sequential)]
 | 
				
			||||||
 | 
					    public unsafe partial struct CCp437Grid
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [StructLayout(LayoutKind.Sequential)]
 | 
					    [StructLayout(LayoutKind.Sequential)]
 | 
				
			||||||
    public unsafe partial struct CByteSlice
 | 
					    public unsafe partial struct CByteSlice
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					@ -238,11 +288,6 @@ namespace ServicePoint.BindGen
 | 
				
			||||||
        public nuint length;
 | 
					        public nuint length;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [StructLayout(LayoutKind.Sequential)]
 | 
					 | 
				
			||||||
    public unsafe partial struct ByteGrid
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [StructLayout(LayoutKind.Sequential)]
 | 
					    [StructLayout(LayoutKind.Sequential)]
 | 
				
			||||||
    public unsafe partial struct Connection
 | 
					    public unsafe partial struct Connection
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					@ -262,17 +307,17 @@ namespace ServicePoint.BindGen
 | 
				
			||||||
    public enum Command
 | 
					    public enum Command
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Clear,
 | 
					        Clear,
 | 
				
			||||||
        HardReset,
 | 
					        Cp437Data,
 | 
				
			||||||
        FadeOut,
 | 
					        BitmapLinearWin,
 | 
				
			||||||
        CharBrightness,
 | 
					 | 
				
			||||||
        Brightness,
 | 
					        Brightness,
 | 
				
			||||||
        BitmapLegacy,
 | 
					        CharBrightness,
 | 
				
			||||||
        BitmapLinear,
 | 
					        BitmapLinear,
 | 
				
			||||||
        BitmapLinearAnd,
 | 
					        BitmapLinearAnd,
 | 
				
			||||||
        BitmapLinearOr,
 | 
					        BitmapLinearOr,
 | 
				
			||||||
        BitmapLinearXor,
 | 
					        BitmapLinearXor,
 | 
				
			||||||
        Cp437Data,
 | 
					        HardReset,
 | 
				
			||||||
        BitmapLinearWin,
 | 
					        FadeOut,
 | 
				
			||||||
 | 
					        BitmapLegacy,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public enum CompressionCode : ushort
 | 
					    public enum CompressionCode : ushort
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										103
									
								
								crates/servicepoint_binding_cs/ServicePoint/BrightnessGrid.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								crates/servicepoint_binding_cs/ServicePoint/BrightnessGrid.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,103 @@
 | 
				
			||||||
 | 
					using ServicePoint.BindGen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ServicePoint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public sealed class BrightnessGrid : SpNativeInstance<BindGen.CBrightnessGrid>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static BrightnessGrid New(int width, int height)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        unsafe
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new BrightnessGrid(NativeMethods.sp_brightness_grid_new((nuint)width, (nuint)height));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static BrightnessGrid Load(int width, int height, Span<byte> bytes)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        unsafe
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fixed (byte* bytesPtr = bytes)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new BrightnessGrid(NativeMethods.sp_brightness_grid_load((nuint)width, (nuint)height, bytesPtr,
 | 
				
			||||||
 | 
					                    (nuint)bytes.Length));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public BrightnessGrid Clone()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        unsafe
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new BrightnessGrid(NativeMethods.sp_brightness_grid_clone(Instance));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public byte this[int x, int y]
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        get
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            unsafe
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return NativeMethods.sp_brightness_grid_get(Instance, (nuint)x, (nuint)y);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        set
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            unsafe
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                NativeMethods.sp_brightness_grid_set(Instance, (nuint)x, (nuint)y, value);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void Fill(byte value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        unsafe
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            NativeMethods.sp_brightness_grid_fill(Instance, value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int Width
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        get
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            unsafe
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return (int)NativeMethods.sp_brightness_grid_width(Instance);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int Height
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        get
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            unsafe
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return (int)NativeMethods.sp_brightness_grid_height(Instance);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Span<byte> Data
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        get
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            unsafe
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var slice = NativeMethods.sp_brightness_grid_unsafe_data_ref(Instance);
 | 
				
			||||||
 | 
					                return new Span<byte>(slice.start, (int)slice.length);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private unsafe BrightnessGrid(BindGen.CBrightnessGrid* instance) : base(instance)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private protected override unsafe void Dealloc()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NativeMethods.sp_brightness_grid_dealloc(Instance);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -61,7 +61,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static Command CharBrightness(int x, int y, ByteGrid grid)
 | 
					    public static Command CharBrightness(int x, int y, BrightnessGrid grid)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unsafe
 | 
					        unsafe
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					@ -113,7 +113,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static Command Cp437Data(int x, int y, ByteGrid byteGrid)
 | 
					    public static Command Cp437Data(int x, int y, Cp437Grid byteGrid)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unsafe
 | 
					        unsafe
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,33 +3,33 @@ using ServicePoint.BindGen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ServicePoint;
 | 
					namespace ServicePoint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
 | 
					public sealed class Cp437Grid : SpNativeInstance<BindGen.CCp437Grid>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public static ByteGrid New(int width, int height)
 | 
					    public static Cp437Grid New(int width, int height)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unsafe
 | 
					        unsafe
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new ByteGrid(NativeMethods.sp_byte_grid_new((nuint)width, (nuint)height));
 | 
					            return new Cp437Grid(NativeMethods.sp_cp437_grid_new((nuint)width, (nuint)height));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static ByteGrid Load(int width, int height, Span<byte> bytes)
 | 
					    public static Cp437Grid Load(int width, int height, Span<byte> bytes)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unsafe
 | 
					        unsafe
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            fixed (byte* bytesPtr = bytes)
 | 
					            fixed (byte* bytesPtr = bytes)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return new ByteGrid(NativeMethods.sp_byte_grid_load((nuint)width, (nuint)height, bytesPtr,
 | 
					                return new Cp437Grid(NativeMethods.sp_cp437_grid_load((nuint)width, (nuint)height, bytesPtr,
 | 
				
			||||||
                    (nuint)bytes.Length));
 | 
					                    (nuint)bytes.Length));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ByteGrid Clone()
 | 
					    public Cp437Grid Clone()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unsafe
 | 
					        unsafe
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new ByteGrid(NativeMethods.sp_byte_grid_clone(Instance));
 | 
					            return new Cp437Grid(NativeMethods.sp_cp437_grid_clone(Instance));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,14 +39,14 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            unsafe
 | 
					            unsafe
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return NativeMethods.sp_byte_grid_get(Instance, (nuint)x, (nuint)y);
 | 
					                return NativeMethods.sp_cp437_grid_get(Instance, (nuint)x, (nuint)y);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        set
 | 
					        set
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            unsafe
 | 
					            unsafe
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                NativeMethods.sp_byte_grid_set(Instance, (nuint)x, (nuint)y, value);
 | 
					                NativeMethods.sp_cp437_grid_set(Instance, (nuint)x, (nuint)y, value);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -85,7 +85,7 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unsafe
 | 
					        unsafe
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            NativeMethods.sp_byte_grid_fill(Instance, value);
 | 
					            NativeMethods.sp_cp437_grid_fill(Instance, value);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -95,7 +95,7 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            unsafe
 | 
					            unsafe
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return (int)NativeMethods.sp_byte_grid_width(Instance);
 | 
					                return (int)NativeMethods.sp_cp437_grid_width(Instance);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -106,7 +106,7 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            unsafe
 | 
					            unsafe
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return (int)NativeMethods.sp_byte_grid_height(Instance);
 | 
					                return (int)NativeMethods.sp_cp437_grid_height(Instance);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -117,18 +117,18 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            unsafe
 | 
					            unsafe
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var slice = NativeMethods.sp_byte_grid_unsafe_data_ref(Instance);
 | 
					                var slice = NativeMethods.sp_cp437_grid_unsafe_data_ref(Instance);
 | 
				
			||||||
                return new Span<byte>(slice.start, (int)slice.length);
 | 
					                return new Span<byte>(slice.start, (int)slice.length);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private unsafe ByteGrid(BindGen.ByteGrid* instance) : base(instance)
 | 
					    private unsafe Cp437Grid(BindGen.CCp437Grid* instance) : base(instance)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private protected override unsafe void Dealloc()
 | 
					    private protected override unsafe void Dealloc()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        NativeMethods.sp_byte_grid_dealloc(Instance);
 | 
					        NativeMethods.sp_cp437_grid_dealloc(Instance);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -7,12 +7,11 @@
 | 
				
			||||||
        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
 | 
					        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
 | 
					        <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
 | 
				
			||||||
        <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | 
					 | 
				
			||||||
    </PropertyGroup>
 | 
					    </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <PropertyGroup>
 | 
					    <PropertyGroup>
 | 
				
			||||||
        <PackageId>ServicePoint</PackageId>
 | 
					        <PackageId>ServicePoint</PackageId>
 | 
				
			||||||
        <Version>0.6.0</Version>
 | 
					        <Version>0.7.0</Version>
 | 
				
			||||||
        <Authors>Repository Authors</Authors>
 | 
					        <Authors>Repository Authors</Authors>
 | 
				
			||||||
        <Company>None</Company>
 | 
					        <Company>None</Company>
 | 
				
			||||||
        <Product>ServicePoint</Product>
 | 
					        <Product>ServicePoint</Product>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,14 +5,14 @@ fn main() {
 | 
				
			||||||
    println!("cargo::rerun-if-changed=build.rs");
 | 
					    println!("cargo::rerun-if-changed=build.rs");
 | 
				
			||||||
    csbindgen::Builder::default()
 | 
					    csbindgen::Builder::default()
 | 
				
			||||||
        .input_extern_file("../servicepoint_binding_c/src/bit_vec.rs")
 | 
					        .input_extern_file("../servicepoint_binding_c/src/bit_vec.rs")
 | 
				
			||||||
        .input_extern_file("../servicepoint_binding_c/src/byte_grid.rs")
 | 
					        .input_extern_file("../servicepoint_binding_c/src/brightness_grid.rs")
 | 
				
			||||||
 | 
					        .input_extern_file("../servicepoint_binding_c/src/cp437_grid.rs")
 | 
				
			||||||
        .input_extern_file("../servicepoint_binding_c/src/command.rs")
 | 
					        .input_extern_file("../servicepoint_binding_c/src/command.rs")
 | 
				
			||||||
        .input_extern_file("../servicepoint_binding_c/src/connection.rs")
 | 
					        .input_extern_file("../servicepoint_binding_c/src/connection.rs")
 | 
				
			||||||
        .input_extern_file("../servicepoint_binding_c/src/pixel_grid.rs")
 | 
					        .input_extern_file("../servicepoint_binding_c/src/pixel_grid.rs")
 | 
				
			||||||
        .input_extern_file("../servicepoint_binding_c/src/lib.rs")
 | 
					        .input_extern_file("../servicepoint_binding_c/src/lib.rs")
 | 
				
			||||||
        .input_extern_file("../servicepoint_binding_c/src/c_slice.rs")
 | 
					        .input_extern_file("../servicepoint_binding_c/src/c_slice.rs")
 | 
				
			||||||
        .input_extern_file("../servicepoint_binding_c/src/packet.rs")
 | 
					        .input_extern_file("../servicepoint_binding_c/src/packet.rs")
 | 
				
			||||||
        .input_extern_file("../servicepoint/src/byte_grid.rs")
 | 
					 | 
				
			||||||
        .input_extern_file("../servicepoint/src/command.rs")
 | 
					        .input_extern_file("../servicepoint/src/command.rs")
 | 
				
			||||||
        .input_extern_file("../servicepoint/src/connection.rs")
 | 
					        .input_extern_file("../servicepoint/src/connection.rs")
 | 
				
			||||||
        .input_extern_file("../servicepoint/src/pixel_grid.rs")
 | 
					        .input_extern_file("../servicepoint/src/pixel_grid.rs")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,16 @@
 | 
				
			||||||
{pkgs ? import <nixpkgs> {}}:
 | 
					{pkgs ? import <nixpkgs> {}}:
 | 
				
			||||||
pkgs.mkShell {
 | 
					pkgs.mkShell {
 | 
				
			||||||
  nativeBuildInputs = with pkgs.buildPackages; [
 | 
					  nativeBuildInputs = with pkgs.buildPackages; [
 | 
				
			||||||
    rustup
 | 
					    rustc cargo gcc rustfmt clippy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pkg-config
 | 
					    pkg-config
 | 
				
			||||||
    xe
 | 
					    xe
 | 
				
			||||||
    lzma
 | 
					    lzma
 | 
				
			||||||
    cargo-tarpaulin
 | 
					    cargo-tarpaulin
 | 
				
			||||||
    gnumake
 | 
					    gnumake
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # dotnet-sdk_8
 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue