Compare commits
	
		
			8 commits
		
	
	
		
			2f7a2dfd62
			...
			de9a09e171
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| de9a09e171 | |||
| 
							 | 
						6a19c5bc6c | ||
| 
							 | 
						a1316b0271 | ||
| 
							 | 
						c534929089 | ||
| 
							 | 
						319ef4572a | ||
| 
							 | 
						62a9969cb5 | ||
| 
							 | 
						0604609fdf | ||
| 
							 | 
						04aa4aa95a | 
					 95 changed files with 357 additions and 12331 deletions
				
			
		| 
						 | 
					@ -1 +0,0 @@
 | 
				
			||||||
use flake
 | 
					 | 
				
			||||||
							
								
								
									
										23
									
								
								.github/workflows/rust.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								.github/workflows/rust.yml
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -30,16 +30,15 @@ jobs:
 | 
				
			||||||
      - name: Run Clippy
 | 
					      - name: Run Clippy
 | 
				
			||||||
        run: cargo clippy --all-targets --all-features
 | 
					        run: cargo clippy --all-targets --all-features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: build default features
 | 
					      - name: no features -- test (without doctest)
 | 
				
			||||||
        run: cargo build --all --verbose
 | 
					        run: cargo test --lib --no-default-features
 | 
				
			||||||
      - name: build default features -- examples
 | 
					 | 
				
			||||||
        run: cargo build --examples --verbose
 | 
					 | 
				
			||||||
      - name: test default features
 | 
					 | 
				
			||||||
        run: cargo test --all --verbose
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: build all features
 | 
					      - name: default features -- test
 | 
				
			||||||
        run: cargo build --all-features --verbose
 | 
					        run: cargo test --all
 | 
				
			||||||
      - name: build all features -- examples
 | 
					      - name: default features -- examples
 | 
				
			||||||
        run: cargo build --all-features --examples --verbose
 | 
					        run: cargo build --examples
 | 
				
			||||||
      - name: test all features
 | 
					
 | 
				
			||||||
        run: cargo test --all --all-features --verbose
 | 
					      - name: all features -- test
 | 
				
			||||||
 | 
					        run: cargo test --all --all-features
 | 
				
			||||||
 | 
					      - name: all features -- examples
 | 
				
			||||||
 | 
					        run: cargo build --examples --all-features
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1143
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1143
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										69
									
								
								Cargo.toml
									
										
									
									
									
								
							
							
						
						
									
										69
									
								
								Cargo.toml
									
										
									
									
									
								
							| 
						 | 
					@ -1,17 +1,60 @@
 | 
				
			||||||
[workspace]
 | 
					[package]
 | 
				
			||||||
resolver = "2"
 | 
					name = "servicepoint"
 | 
				
			||||||
members = [
 | 
					 | 
				
			||||||
    "crates/servicepoint",
 | 
					 | 
				
			||||||
    "crates/servicepoint_binding_c",
 | 
					 | 
				
			||||||
    "crates/servicepoint_binding_c/examples/lang_c",
 | 
					 | 
				
			||||||
    "crates/servicepoint_binding_uniffi"
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[workspace.package]
 | 
					 | 
				
			||||||
version = "0.13.1"
 | 
					version = "0.13.1"
 | 
				
			||||||
 | 
					publish = true
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					license = "GPL-3.0-or-later"
 | 
				
			||||||
 | 
					description = "A rust library for the CCCB Service Point Display."
 | 
				
			||||||
 | 
					homepage = "https://docs.rs/crate/servicepoint"
 | 
				
			||||||
 | 
					repository = "https://git.berlin.ccc.de/servicepoint/servicepoint"
 | 
				
			||||||
 | 
					readme = "README.md"
 | 
				
			||||||
 | 
					keywords = ["cccb", "cccb-servicepoint"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[workspace.lints.rust]
 | 
					[lib]
 | 
				
			||||||
 | 
					crate-type = ["rlib"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					log = "0.4"
 | 
				
			||||||
 | 
					bitvec = "1.0"
 | 
				
			||||||
 | 
					flate2 = { version = "1.0", optional = true }
 | 
				
			||||||
 | 
					bzip2 = { version = "0.5", optional = true }
 | 
				
			||||||
 | 
					zstd = { version = "0.13", optional = true }
 | 
				
			||||||
 | 
					rust-lzma = { version = "0.6", optional = true }
 | 
				
			||||||
 | 
					rand = { version = "0.8", optional = true }
 | 
				
			||||||
 | 
					tungstenite = { version = "0.26", optional = true }
 | 
				
			||||||
 | 
					once_cell = { version = "1.20", optional = true }
 | 
				
			||||||
 | 
					thiserror = "2.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[features]
 | 
				
			||||||
 | 
					default = ["compression_lzma", "protocol_udp", "cp437"]
 | 
				
			||||||
 | 
					compression_zlib = ["dep:flate2"]
 | 
				
			||||||
 | 
					compression_bzip2 = ["dep:bzip2"]
 | 
				
			||||||
 | 
					compression_lzma = ["dep:rust-lzma"]
 | 
				
			||||||
 | 
					compression_zstd = ["dep:zstd"]
 | 
				
			||||||
 | 
					all_compressions = ["compression_zlib", "compression_bzip2", "compression_lzma", "compression_zstd"]
 | 
				
			||||||
 | 
					rand = ["dep:rand"]
 | 
				
			||||||
 | 
					protocol_udp = []
 | 
				
			||||||
 | 
					protocol_websocket = ["dep:tungstenite"]
 | 
				
			||||||
 | 
					cp437 = ["dep:once_cell"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[example]]
 | 
				
			||||||
 | 
					name = "random_brightness"
 | 
				
			||||||
 | 
					required-features = ["rand"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[example]]
 | 
				
			||||||
 | 
					name = "game_of_life"
 | 
				
			||||||
 | 
					required-features = ["rand"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[example]]
 | 
				
			||||||
 | 
					name = "websocket"
 | 
				
			||||||
 | 
					required-features = ["protocol_websocket"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dev-dependencies]
 | 
				
			||||||
 | 
					# for examples
 | 
				
			||||||
 | 
					clap = { version = "4.5", features = ["derive"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[lints.rust]
 | 
				
			||||||
missing-docs = "warn"
 | 
					missing-docs = "warn"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[workspace.dependencies]
 | 
					[package.metadata.docs.rs]
 | 
				
			||||||
thiserror = "2.0"
 | 
					all-features = true
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										94
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										94
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
					@ -7,19 +7,87 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall. It is called  "Service Point
 | 
					In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall. It is called  "Service Point
 | 
				
			||||||
Display" or "Airport Display".
 | 
					Display" or "Airport Display".
 | 
				
			||||||
This repository contains a library for parsing, encoding and sending packets to this display via UDP in multiple
 | 
					 | 
				
			||||||
programming languages.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
This project moved to [git.berlin.ccc.de/servicepoint/servicepoint](https://git.berlin.ccc.de/servicepoint/servicepoint). 
 | 
					This crate contains a library for parsing, encoding and sending packets to this display via UDP.
 | 
				
			||||||
 | 
					The library itself is written in Rust, but can be used from multiple languages
 | 
				
			||||||
 | 
					via [language bindings](#supported-language-bindings).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This project moved
 | 
				
			||||||
 | 
					to [git.berlin.ccc.de/servicepoint/servicepoint](https://git.berlin.ccc.de/servicepoint/servicepoint).
 | 
				
			||||||
The [GitHub repository](https://github.com/cccb/servicepoint) remains available as a mirror.
 | 
					The [GitHub repository](https://github.com/cccb/servicepoint) remains available as a mirror.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Take a look at the contained crates for language specific information:
 | 
					## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Crate                       | Languages                         | Readme                                                                      |
 | 
					```rust no_run
 | 
				
			||||||
|-----------------------------|-----------------------------------|-----------------------------------------------------------------------------|
 | 
					// everything you need is in the top-level
 | 
				
			||||||
| servicepoint                | Rust                              | [servicepoint](crates/servicepoint/README.md)                               |
 | 
					use servicepoint::*;
 | 
				
			||||||
| servicepoint_binding_c      | C / C++                           | [servicepoint_binding_c](crates/servicepoint_binding_c/README.md)           |
 | 
					
 | 
				
			||||||
| servicepoint_binding_uniffi | C# / Python / Go / Kotlin / Swift | [servicepoint_binding_uniffi](crates/servicepoint_binding_uniffi/README.md) |
 | 
					fn main() {
 | 
				
			||||||
 | 
					    // establish connection
 | 
				
			||||||
 | 
					    let connection = Connection::open("172.23.42.29:2342")
 | 
				
			||||||
 | 
					        .expect("connection failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // clear screen content
 | 
				
			||||||
 | 
					    connection.send(Command::Clear)
 | 
				
			||||||
 | 
					        .expect("send failed");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					More examples are available in the crate.
 | 
				
			||||||
 | 
					Execute `cargo run --example` for a list of available examples and `cargo run --example <name>` to run one.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Installation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					cargo add servicepoint
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					or
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```toml
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					servicepoint = "0.13.1"
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Note on stability
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This library can be used for creative project or just to play around with the display.
 | 
				
			||||||
 | 
					A decent coverage by unit tests prevents major problems and I also test this with my own projects, which mostly use
 | 
				
			||||||
 | 
					up-to-date versions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					That being said, the API is still being worked on.
 | 
				
			||||||
 | 
					Expect breaking changes with every minor version bump.
 | 
				
			||||||
 | 
					There should be no breaking changes in patch releases, but there may also be features hiding in those.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					All of this means for you: please specify the full version including patch in your Cargo.toml until 1.0 is released.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This library has multiple optional dependencies.
 | 
				
			||||||
 | 
					You can choose to (not) include them by toggling the related features.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Name               | Default | Description                                  | Dependencies                                        |
 | 
				
			||||||
 | 
					|--------------------|---------|----------------------------------------------|-----------------------------------------------------|
 | 
				
			||||||
 | 
					| protocol_udp       | true    | `Connection::Udp`                            |                                                     |
 | 
				
			||||||
 | 
					| cp437              | true    | Conversion to and from CP-437                | [once_cell](https://crates.io/crates/once_cell)     |
 | 
				
			||||||
 | 
					| compression_lzma   | true    | Enable additional compression algo           | [rust-lzma](https://crates.io/crates/rust-lzma)     |
 | 
				
			||||||
 | 
					| compression_zlib   | false   | Enable additional compression algo           | [flate2](https://crates.io/crates/flate2)           |
 | 
				
			||||||
 | 
					| compression_bzip2  | false   | Enable additional compression algo           | [bzip2](https://crates.io/crates/bzip2)             |
 | 
				
			||||||
 | 
					| compression_zstd   | false   | Enable additional compression algo           | [zstd](https://crates.io/crates/zstd)               |
 | 
				
			||||||
 | 
					| protocol_websocket | false   | `Connection::WebSocket`                      | [tungstenite](https://crates.io/crates/tungstenite) |
 | 
				
			||||||
 | 
					| rand               | false   | `impl Distribution<Brightness> for Standard` | [rand](https://crates.io/crates/rand)               |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Supported language bindings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Language  | Support level | Repo                                                                                                                                             |
 | 
				
			||||||
 | 
					|-----------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
 | 
				
			||||||
 | 
					| .NET (C#) | Full          | [servicepoint-binding-csharp](https://git.berlin.ccc.de/servicepoint/servicepoint-binding-csharp) contains bindings and a `.csproj` to reference |
 | 
				
			||||||
 | 
					| C         | Full          | [servicepoint-binding-c](https://git.berlin.ccc.de/servicepoint/servicepoint-binding-c) contains a header and a library to link against          |
 | 
				
			||||||
 | 
					| Ruby      | Working       | [servicepoint-binding-ruby](https://git.berlin.ccc.de/servicepoint/servicepoint-binding-ruby) contains bindings                                  |
 | 
				
			||||||
 | 
					| Python    | Unsupported   | bindings can be generated from [servicepoint-binding-uniffi](https://git.berlin.ccc.de/servicepoint/servicepoint-binding-uniffi), tested once    |
 | 
				
			||||||
 | 
					| Go        | Unsupported   | bindings can be generated from [servicepoint-binding-uniffi](https://git.berlin.ccc.de/servicepoint/servicepoint-binding-uniffi)                 |
 | 
				
			||||||
 | 
					| Kotlin    | Unsupported   | bindings can be generated from [servicepoint-binding-uniffi](https://git.berlin.ccc.de/servicepoint/servicepoint-binding-uniffi)                 |
 | 
				
			||||||
 | 
					| Swift     | Unsupported   | bindings can be generated from [servicepoint-binding-uniffi](https://git.berlin.ccc.de/servicepoint/servicepoint-binding-uniffi)                 |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Projects using the library
 | 
					## Projects using the library
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,12 +99,14 @@ Take a look at the contained crates for language specific information:
 | 
				
			||||||
    - animations that play on the display
 | 
					    - animations that play on the display
 | 
				
			||||||
- tanks game (C#): [servicepoint-tanks](https://github.com/kaesaecracker/cccb-tanks-cs)
 | 
					- tanks game (C#): [servicepoint-tanks](https://github.com/kaesaecracker/cccb-tanks-cs)
 | 
				
			||||||
- cellular automata slideshow (rust): [servicepoint-life](https://github.com/kaesaecracker/servicepoint-life)
 | 
					- cellular automata slideshow (rust): [servicepoint-life](https://github.com/kaesaecracker/servicepoint-life)
 | 
				
			||||||
- partial typescript implementation inspired by this library and browser stream: [cccb-servicepoint-browser](https://github.com/SamuelScheit/cccb-servicepoint-browser)
 | 
					- partial typescript implementation inspired by this library and browser
 | 
				
			||||||
- a CLI: [servicepoint-cli](https://git.berlin.ccc.de/servicepoint/servicepoint-cli)
 | 
					  stream: [cccb-servicepoint-browser](https://github.com/SamuelScheit/cccb-servicepoint-browser)
 | 
				
			||||||
 | 
					- a CLI, can also share your screen: [servicepoint-cli](https://git.berlin.ccc.de/servicepoint/servicepoint-cli)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To add yourself to the list, open a pull request.
 | 
					To add yourself to the list, open a pull request.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can also check out [awesome-servicepoint](https://github.com/stars/kaesaecracker/lists/awesome-servicepoint) for a bigger collection of projects, including some not related to this library.
 | 
					You can also check out [awesome-servicepoint](https://github.com/stars/kaesaecracker/lists/awesome-servicepoint) for a
 | 
				
			||||||
 | 
					bigger collection of projects, including some not related to this library.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you have access, there is even more software linked in [the wiki](https://wiki.berlin.ccc.de/LED-Riesendisplay).
 | 
					If you have access, there is even more software linked in [the wiki](https://wiki.berlin.ccc.de/LED-Riesendisplay).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,60 +0,0 @@
 | 
				
			||||||
[package]
 | 
					 | 
				
			||||||
name = "servicepoint"
 | 
					 | 
				
			||||||
version.workspace = true
 | 
					 | 
				
			||||||
publish = true
 | 
					 | 
				
			||||||
edition = "2021"
 | 
					 | 
				
			||||||
license = "GPL-3.0-or-later"
 | 
					 | 
				
			||||||
description = "A rust library for the CCCB Service Point Display."
 | 
					 | 
				
			||||||
homepage = "https://docs.rs/crate/servicepoint"
 | 
					 | 
				
			||||||
repository = "https://git.berlin.ccc.de/servicepoint/servicepoint"
 | 
					 | 
				
			||||||
readme = "README.md"
 | 
					 | 
				
			||||||
keywords = ["cccb", "cccb-servicepoint"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[lib]
 | 
					 | 
				
			||||||
crate-type = ["rlib"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies]
 | 
					 | 
				
			||||||
log = "0.4"
 | 
					 | 
				
			||||||
bitvec = "1.0"
 | 
					 | 
				
			||||||
flate2 = { version = "1.0", optional = true }
 | 
					 | 
				
			||||||
bzip2 = { version = "0.5", optional = true }
 | 
					 | 
				
			||||||
zstd = { version = "0.13", optional = true }
 | 
					 | 
				
			||||||
rust-lzma = { version = "0.6", optional = true }
 | 
					 | 
				
			||||||
rand = { version = "0.8", optional = true }
 | 
					 | 
				
			||||||
tungstenite = { version = "0.26", optional = true }
 | 
					 | 
				
			||||||
once_cell = { version = "1.20", optional = true }
 | 
					 | 
				
			||||||
thiserror.workspace = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[features]
 | 
					 | 
				
			||||||
default = ["compression_lzma", "protocol_udp", "cp437"]
 | 
					 | 
				
			||||||
compression_zlib = ["dep:flate2"]
 | 
					 | 
				
			||||||
compression_bzip2 = ["dep:bzip2"]
 | 
					 | 
				
			||||||
compression_lzma = ["dep:rust-lzma"]
 | 
					 | 
				
			||||||
compression_zstd = ["dep:zstd"]
 | 
					 | 
				
			||||||
all_compressions = ["compression_zlib", "compression_bzip2", "compression_lzma", "compression_zstd"]
 | 
					 | 
				
			||||||
rand = ["dep:rand"]
 | 
					 | 
				
			||||||
protocol_udp = []
 | 
					 | 
				
			||||||
protocol_websocket = ["dep:tungstenite"]
 | 
					 | 
				
			||||||
cp437 = ["dep:once_cell"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[example]]
 | 
					 | 
				
			||||||
name = "random_brightness"
 | 
					 | 
				
			||||||
required-features = ["rand"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[example]]
 | 
					 | 
				
			||||||
name = "game_of_life"
 | 
					 | 
				
			||||||
required-features = ["rand"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[example]]
 | 
					 | 
				
			||||||
name = "websocket"
 | 
					 | 
				
			||||||
required-features = ["protocol_websocket"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dev-dependencies]
 | 
					 | 
				
			||||||
# for examples
 | 
					 | 
				
			||||||
clap = { version = "4.5", features = ["derive"] }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[lints]
 | 
					 | 
				
			||||||
workspace = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[package.metadata.docs.rs]
 | 
					 | 
				
			||||||
all-features = true
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,67 +0,0 @@
 | 
				
			||||||
# servicepoint
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[](https://crates.io/crates/servicepoint)
 | 
					 | 
				
			||||||
[](https://crates.io/crates/servicepoint)
 | 
					 | 
				
			||||||
[](https://docs.rs/servicepoint/latest/servicepoint/)
 | 
					 | 
				
			||||||
[](../../LICENSE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall. It is called  "Service Point
 | 
					 | 
				
			||||||
Display" or "Airport Display".
 | 
					 | 
				
			||||||
This crate contains a library for parsing, encoding and sending packets to this display via UDP.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Installation
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
cargo add servicepoint
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
or
 | 
					 | 
				
			||||||
```toml
 | 
					 | 
				
			||||||
[dependencies]
 | 
					 | 
				
			||||||
servicepoint = "0.13.1"
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Examples
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```rust no_run
 | 
					 | 
				
			||||||
fn main() {
 | 
					 | 
				
			||||||
    // establish connection
 | 
					 | 
				
			||||||
    let connection = servicepoint::Connection::open("172.23.42.29:2342")
 | 
					 | 
				
			||||||
        .expect("connection failed");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // clear screen content
 | 
					 | 
				
			||||||
    connection.send(servicepoint::Command::Clear)
 | 
					 | 
				
			||||||
        .expect("send failed");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
More examples are available in the crate.
 | 
					 | 
				
			||||||
Execute `cargo run --example` for a list of available examples and `cargo run --example <name>` to run one.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Note on stability
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This library can be used for creative project or just to play around with the display.
 | 
					 | 
				
			||||||
A decent coverage by unit tests prevents major problems and I also test this with my own projects, which mostly use up-to-date versions.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
That being said, the API is still being worked on.
 | 
					 | 
				
			||||||
Expect minor breaking changes with every version bump.
 | 
					 | 
				
			||||||
Please specify the full version including patch in your Cargo.toml until 1.0 is released.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Features
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This library has multiple optional dependencies.
 | 
					 | 
				
			||||||
You can choose to (not) include them by toggling the related features.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| Name               | Default | Description                                |
 | 
					 | 
				
			||||||
|--------------------|---------|--------------------------------------------|
 | 
					 | 
				
			||||||
| compression_zlib   | false   | Enable additional compression algo         |
 | 
					 | 
				
			||||||
| compression_bzip2  | false   | Enable additional compression algo         |
 | 
					 | 
				
			||||||
| compression_lzma   | true    | Enable additional compression algo         |
 | 
					 | 
				
			||||||
| compression_zstd   | false   | Enable additional compression algo         |
 | 
					 | 
				
			||||||
| protocol_udp       | true    | Connection::Udp                            |
 | 
					 | 
				
			||||||
| protocol_websocket | false   | Connection::WebSocket                      |
 | 
					 | 
				
			||||||
| rand               | false   | impl Distribution<Brightness> for Standard |
 | 
					 | 
				
			||||||
| cp437              | true    | Conversion to and from CP-437              |
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Everything else
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Look at the main project [README](https://git.berlin.ccc.de/servicepoint/servicepoint/src/branch/main/README.md) for further information.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,29 +0,0 @@
 | 
				
			||||||
[package]
 | 
					 | 
				
			||||||
name = "servicepoint_binding_c"
 | 
					 | 
				
			||||||
version.workspace = true
 | 
					 | 
				
			||||||
publish = true
 | 
					 | 
				
			||||||
edition = "2021"
 | 
					 | 
				
			||||||
license = "GPL-3.0-or-later"
 | 
					 | 
				
			||||||
description = "C bindings for the servicepoint crate."
 | 
					 | 
				
			||||||
homepage = "https://docs.rs/crate/servicepoint_binding_c"
 | 
					 | 
				
			||||||
repository = "https://git.berlin.ccc.de/servicepoint/servicepoint"
 | 
					 | 
				
			||||||
readme = "README.md"
 | 
					 | 
				
			||||||
links = "servicepoint"
 | 
					 | 
				
			||||||
keywords = ["cccb", "cccb-servicepoint", "cbindgen"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[lib]
 | 
					 | 
				
			||||||
crate-type = ["staticlib", "cdylib", "rlib"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[build-dependencies]
 | 
					 | 
				
			||||||
cbindgen = "0.27.0"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.servicepoint]
 | 
					 | 
				
			||||||
version = "0.13.1"
 | 
					 | 
				
			||||||
path = "../servicepoint"
 | 
					 | 
				
			||||||
features = ["all_compressions"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[lints]
 | 
					 | 
				
			||||||
workspace = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[package.metadata.docs.rs]
 | 
					 | 
				
			||||||
all-features = true
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,63 +0,0 @@
 | 
				
			||||||
# servicepoint_binding_c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[](https://crates.io/crates/servicepoint)
 | 
					 | 
				
			||||||
[](https://crates.io/crates/servicepoint)
 | 
					 | 
				
			||||||
[](https://docs.rs/servicepoint/latest/servicepoint/)
 | 
					 | 
				
			||||||
[](../../LICENSE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall. 
 | 
					 | 
				
			||||||
It is called  "Service Point Display" or "Airport Display".
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This crate contains C bindings for the `servicepoint` library, enabling users to parse, encode and send packets to this display via UDP.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Examples
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```c++
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include "servicepoint.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main(void) {
 | 
					 | 
				
			||||||
    SPConnection *connection = sp_connection_open("172.23.42.29:2342");
 | 
					 | 
				
			||||||
    if (connection == NULL)
 | 
					 | 
				
			||||||
        return 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
 | 
					 | 
				
			||||||
    sp_bitmap_fill(pixels, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
 | 
					 | 
				
			||||||
    while (sp_connection_send_command(connection, sp_command_clone(command)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sp_command_free(command);
 | 
					 | 
				
			||||||
    sp_connection_free(connection);
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
A full example including Makefile is available as part of this crate.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Note on stability
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This library is still in early development.
 | 
					 | 
				
			||||||
You can absolutely use it, and it works, but expect minor breaking changes with every version bump.
 | 
					 | 
				
			||||||
Please specify the full version including patch in your Cargo.toml until 1.0 is released.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Installation
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Copy the header to your project and compile against.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
You have the choice of linking statically (recommended) or dynamically.
 | 
					 | 
				
			||||||
- The C example shows how to link statically against the `staticlib` variant.
 | 
					 | 
				
			||||||
- When linked dynamically, you have to provide the `cdylib` at runtime in the _same_ version, as there are no API/ABI guarantees yet.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Notes on differences to rust library
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- function names are: `sp_` \<struct_name\> \<rust name\>.
 | 
					 | 
				
			||||||
- Instances get consumed in the same way they do when writing rust code. Do not use an instance after an (implicit!) free.
 | 
					 | 
				
			||||||
- Option<T> or Result<T, E> turn into nullable return values - check for NULL!
 | 
					 | 
				
			||||||
- There are no specifics for C++ here yet. You might get a nicer header when generating directly for C++, but it should be usable.
 | 
					 | 
				
			||||||
- Reading and writing to instances concurrently is not safe. Only reading concurrently is safe.
 | 
					 | 
				
			||||||
- documentation is included in the header and available [online](https://docs.rs/servicepoint_binding_c/latest/servicepoint_binding_c/)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Everything else
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Look at the main project [README](https://git.berlin.ccc.de/servicepoint/servicepoint/src/branch/main/README.md) for further information.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,33 +0,0 @@
 | 
				
			||||||
//! Build script generating the header for the `servicepoint` C library.
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! When the environment variable `SERVICEPOINT_HEADER_OUT` is set, the header is copied there from
 | 
					 | 
				
			||||||
//! the out directory. This can be used to use the build script as a command line tool from other
 | 
					 | 
				
			||||||
//! build tools.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use std::{env, fs::copy};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use cbindgen::{generate_with_config, Config};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn main() {
 | 
					 | 
				
			||||||
    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
 | 
					 | 
				
			||||||
    println!("cargo::rerun-if-changed={crate_dir}");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let config =
 | 
					 | 
				
			||||||
        Config::from_file(crate_dir.clone() + "/cbindgen.toml").unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let output_dir = env::var("OUT_DIR").unwrap();
 | 
					 | 
				
			||||||
    let header_file = output_dir.clone() + "/servicepoint.h";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    generate_with_config(crate_dir, config)
 | 
					 | 
				
			||||||
        .unwrap()
 | 
					 | 
				
			||||||
        .write_to_file(&header_file);
 | 
					 | 
				
			||||||
    println!("cargo:include={output_dir}");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    println!("cargo::rerun-if-env-changed=SERVICEPOINT_HEADER_OUT");
 | 
					 | 
				
			||||||
    if let Ok(header_out) = env::var("SERVICEPOINT_HEADER_OUT") {
 | 
					 | 
				
			||||||
        let header_copy = header_out + "/servicepoint.h";
 | 
					 | 
				
			||||||
        println!("cargo:warning=Copying header to {header_copy}");
 | 
					 | 
				
			||||||
        copy(header_file, &header_copy).unwrap();
 | 
					 | 
				
			||||||
        println!("cargo::rerun-if-changed={header_copy}");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,36 +0,0 @@
 | 
				
			||||||
language = "C"
 | 
					 | 
				
			||||||
include_version = true
 | 
					 | 
				
			||||||
cpp_compat = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
############################ Code Style Options ################################
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
braces = "SameLine"
 | 
					 | 
				
			||||||
line_length = 80
 | 
					 | 
				
			||||||
tab_width = 4
 | 
					 | 
				
			||||||
documentation = true
 | 
					 | 
				
			||||||
documentation_style = "auto"
 | 
					 | 
				
			||||||
documentation_length = "full"
 | 
					 | 
				
			||||||
line_endings = "LF"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
############################# Codegen Options ##################################
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
style = "type"
 | 
					 | 
				
			||||||
usize_is_size_t = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# this is needed because otherwise the order in the C# bindings is different on different machines
 | 
					 | 
				
			||||||
sort_by = "Name"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[parse]
 | 
					 | 
				
			||||||
parse_deps = false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[parse.expand]
 | 
					 | 
				
			||||||
all_features = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[export]
 | 
					 | 
				
			||||||
include = []
 | 
					 | 
				
			||||||
exclude = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[enum]
 | 
					 | 
				
			||||||
rename_variants = "QualifiedScreamingSnakeCase"
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,14 +0,0 @@
 | 
				
			||||||
[package]
 | 
					 | 
				
			||||||
name = "lang_c"
 | 
					 | 
				
			||||||
version = "0.1.0"
 | 
					 | 
				
			||||||
edition = "2021"
 | 
					 | 
				
			||||||
publish = false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[lib]
 | 
					 | 
				
			||||||
test = false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[build-dependencies]
 | 
					 | 
				
			||||||
cc = "1.2"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies]
 | 
					 | 
				
			||||||
servicepoint_binding_c = { path = "../.." }
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,34 +0,0 @@
 | 
				
			||||||
CC := gcc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
THIS_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
 | 
					 | 
				
			||||||
REPO_ROOT := $(THIS_DIR)/../../../..
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
build: out/lang_c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
clean:
 | 
					 | 
				
			||||||
	rm -r out || true
 | 
					 | 
				
			||||||
	rm include/servicepoint.h || true
 | 
					 | 
				
			||||||
	cargo clean
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
run: out/lang_c
 | 
					 | 
				
			||||||
	out/lang_c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PHONY: build clean dependencies run
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out/lang_c: dependencies src/main.c
 | 
					 | 
				
			||||||
	mkdir -p out || true
 | 
					 | 
				
			||||||
	${CC} src/main.c \
 | 
					 | 
				
			||||||
		-I include \
 | 
					 | 
				
			||||||
		-L $(REPO_ROOT)/target/release \
 | 
					 | 
				
			||||||
		-Wl,-Bstatic -lservicepoint_binding_c \
 | 
					 | 
				
			||||||
		-Wl,-Bdynamic -llzma \
 | 
					 | 
				
			||||||
		-o out/lang_c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dependencies: FORCE
 | 
					 | 
				
			||||||
	mkdir -p include || true
 | 
					 | 
				
			||||||
	# generate servicepoint header and binary to link against
 | 
					 | 
				
			||||||
	SERVICEPOINT_HEADER_OUT=$(THIS_DIR)/include cargo build \
 | 
					 | 
				
			||||||
		--manifest-path=$(REPO_ROOT)/crates/servicepoint_binding_c/Cargo.toml \
 | 
					 | 
				
			||||||
		--release
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FORCE: ;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,17 +0,0 @@
 | 
				
			||||||
const SP_INCLUDE: &str = "DEP_SERVICEPOINT_INCLUDE";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn main() {
 | 
					 | 
				
			||||||
    println!("cargo::rerun-if-changed=src/main.c");
 | 
					 | 
				
			||||||
    println!("cargo::rerun-if-changed=build.rs");
 | 
					 | 
				
			||||||
    println!("cargo::rerun-if-env-changed={SP_INCLUDE}");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let sp_include =
 | 
					 | 
				
			||||||
        std::env::var_os(SP_INCLUDE).unwrap().into_string().unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // this builds a lib, this is only to check that the example compiles
 | 
					 | 
				
			||||||
    let mut cc = cc::Build::new();
 | 
					 | 
				
			||||||
    cc.file("src/main.c");
 | 
					 | 
				
			||||||
    cc.include(&sp_include);
 | 
					 | 
				
			||||||
    cc.opt_level(2);
 | 
					 | 
				
			||||||
    cc.compile("lang_c");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1 +0,0 @@
 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,17 +0,0 @@
 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include "servicepoint.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main(void) {
 | 
					 | 
				
			||||||
    SPConnection *connection = sp_connection_open("localhost:2342");
 | 
					 | 
				
			||||||
    if (connection == NULL)
 | 
					 | 
				
			||||||
        return 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
 | 
					 | 
				
			||||||
    sp_bitmap_fill(pixels, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, SP_COMPRESSION_CODE_UNCOMPRESSED);
 | 
					 | 
				
			||||||
    sp_connection_send_command(connection, command);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sp_connection_free(connection);
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,296 +0,0 @@
 | 
				
			||||||
//! C functions for interacting with [SPBitmap]s
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! prefix `sp_bitmap_`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use servicepoint::{DataRef, Grid};
 | 
					 | 
				
			||||||
use std::ptr::NonNull;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::byte_slice::SPByteSlice;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A grid of pixels.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Examples
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// ```C
 | 
					 | 
				
			||||||
/// Cp437Grid grid = sp_bitmap_new(8, 3);
 | 
					 | 
				
			||||||
/// sp_bitmap_fill(grid, true);
 | 
					 | 
				
			||||||
/// sp_bitmap_set(grid, 0, 0, false);
 | 
					 | 
				
			||||||
/// sp_bitmap_free(grid);
 | 
					 | 
				
			||||||
/// ```
 | 
					 | 
				
			||||||
pub struct SPBitmap(pub(crate) servicepoint::Bitmap);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Creates a new [SPBitmap] with the specified dimensions.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `width`: size in pixels in x-direction
 | 
					 | 
				
			||||||
/// - `height`: size in pixels in y-direction
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: [SPBitmap] initialized to all pixels off. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when the width is not dividable by 8
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - the returned instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_bitmap_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitmap_new(
 | 
					 | 
				
			||||||
    width: usize,
 | 
					 | 
				
			||||||
    height: usize,
 | 
					 | 
				
			||||||
) -> NonNull<SPBitmap> {
 | 
					 | 
				
			||||||
    let result = Box::new(SPBitmap(servicepoint::Bitmap::new(width, height)));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Creates a new [SPBitmap] with a size matching the screen.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: [SPBitmap] initialized to all pixels off. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - the returned instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling [sp_bitmap_free].
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull<SPBitmap> {
 | 
					 | 
				
			||||||
    let result = Box::new(SPBitmap(servicepoint::Bitmap::max_sized()));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Loads a [SPBitmap] with the specified dimensions from the provided data.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `width`: size in pixels in x-direction
 | 
					 | 
				
			||||||
/// - `height`: size in pixels in y-direction
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: [SPBitmap] that contains a copy of the provided data. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `data` is NULL
 | 
					 | 
				
			||||||
/// - when the dimensions and data size do not match exactly.
 | 
					 | 
				
			||||||
/// - when the width is not dividable by 8
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `data` points to a valid memory location of at least `data_length` bytes in size.
 | 
					 | 
				
			||||||
/// - the returned instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_bitmap_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitmap_load(
 | 
					 | 
				
			||||||
    width: usize,
 | 
					 | 
				
			||||||
    height: usize,
 | 
					 | 
				
			||||||
    data: *const u8,
 | 
					 | 
				
			||||||
    data_length: usize,
 | 
					 | 
				
			||||||
) -> NonNull<SPBitmap> {
 | 
					 | 
				
			||||||
    assert!(!data.is_null());
 | 
					 | 
				
			||||||
    let data = std::slice::from_raw_parts(data, data_length);
 | 
					 | 
				
			||||||
    let result =
 | 
					 | 
				
			||||||
        Box::new(SPBitmap(servicepoint::Bitmap::load(width, height, data)));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Clones a [SPBitmap].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bitmap` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap` points to a valid [SPBitmap]
 | 
					 | 
				
			||||||
/// - `bitmap` is not written to concurrently
 | 
					 | 
				
			||||||
/// - the returned instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_bitmap_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitmap_clone(
 | 
					 | 
				
			||||||
    bitmap: *const SPBitmap,
 | 
					 | 
				
			||||||
) -> NonNull<SPBitmap> {
 | 
					 | 
				
			||||||
    assert!(!bitmap.is_null());
 | 
					 | 
				
			||||||
    let result = Box::new(SPBitmap((*bitmap).0.clone()));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Deallocates a [SPBitmap].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bitmap` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap` points to a valid [SPBitmap]
 | 
					 | 
				
			||||||
/// - `bitmap` is not used concurrently or after bitmap call
 | 
					 | 
				
			||||||
/// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand]
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// [SPCommand]: [crate::SPCommand]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) {
 | 
					 | 
				
			||||||
    assert!(!bitmap.is_null());
 | 
					 | 
				
			||||||
    _ = Box::from_raw(bitmap);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the current value at the specified position in the [SPBitmap].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap`: instance to read from
 | 
					 | 
				
			||||||
/// - `x` and `y`: position of the cell to read
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bitmap` is NULL
 | 
					 | 
				
			||||||
/// - when accessing `x` or `y` out of bounds
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap` points to a valid [SPBitmap]
 | 
					 | 
				
			||||||
/// - `bitmap` is not written to concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitmap_get(
 | 
					 | 
				
			||||||
    bitmap: *const SPBitmap,
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
) -> bool {
 | 
					 | 
				
			||||||
    assert!(!bitmap.is_null());
 | 
					 | 
				
			||||||
    (*bitmap).0.get(x, y)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sets the value of the specified position in the [SPBitmap].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap`: instance to write to
 | 
					 | 
				
			||||||
/// - `x` and `y`: position of the cell
 | 
					 | 
				
			||||||
/// - `value`: the value to write to the cell
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: old value of the cell
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bitmap` is NULL
 | 
					 | 
				
			||||||
/// - when accessing `x` or `y` out of bounds
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap` points to a valid [SPBitmap]
 | 
					 | 
				
			||||||
/// - `bitmap` is not written to or read from concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitmap_set(
 | 
					 | 
				
			||||||
    bitmap: *mut SPBitmap,
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
    value: bool,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    assert!(!bitmap.is_null());
 | 
					 | 
				
			||||||
    (*bitmap).0.set(x, y, value);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sets the state of all pixels in the [SPBitmap].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap`: instance to write to
 | 
					 | 
				
			||||||
/// - `value`: the value to set all pixels to
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bitmap` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap` points to a valid [SPBitmap]
 | 
					 | 
				
			||||||
/// - `bitmap` is not written to or read from concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitmap_fill(bitmap: *mut SPBitmap, value: bool) {
 | 
					 | 
				
			||||||
    assert!(!bitmap.is_null());
 | 
					 | 
				
			||||||
    (*bitmap).0.fill(value);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the width in pixels of the [SPBitmap] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap`: instance to read from
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bitmap` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap` points to a valid [SPBitmap]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitmap_width(bitmap: *const SPBitmap) -> usize {
 | 
					 | 
				
			||||||
    assert!(!bitmap.is_null());
 | 
					 | 
				
			||||||
    (*bitmap).0.width()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the height in pixels of the [SPBitmap] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap`: instance to read from
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bitmap` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap` points to a valid [SPBitmap]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitmap_height(bitmap: *const SPBitmap) -> usize {
 | 
					 | 
				
			||||||
    assert!(!bitmap.is_null());
 | 
					 | 
				
			||||||
    (*bitmap).0.height()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets an unsafe reference to the data of the [SPBitmap] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bitmap` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap` points to a valid [SPBitmap]
 | 
					 | 
				
			||||||
/// - the returned memory range is never accessed after the passed [SPBitmap] has been freed
 | 
					 | 
				
			||||||
/// - the returned memory range is never accessed concurrently, either via the [SPBitmap] or directly
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitmap_unsafe_data_ref(
 | 
					 | 
				
			||||||
    bitmap: *mut SPBitmap,
 | 
					 | 
				
			||||||
) -> SPByteSlice {
 | 
					 | 
				
			||||||
    assert!(!bitmap.is_null());
 | 
					 | 
				
			||||||
    let data = (*bitmap).0.data_ref_mut();
 | 
					 | 
				
			||||||
    SPByteSlice {
 | 
					 | 
				
			||||||
        start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
 | 
					 | 
				
			||||||
        length: data.len(),
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,283 +0,0 @@
 | 
				
			||||||
//! C functions for interacting with [SPBitVec]s
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! prefix `sp_bitvec_`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::SPByteSlice;
 | 
					 | 
				
			||||||
use std::ptr::NonNull;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A vector of bits
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Examples
 | 
					 | 
				
			||||||
/// ```C
 | 
					 | 
				
			||||||
/// SPBitVec vec = sp_bitvec_new(8);
 | 
					 | 
				
			||||||
/// sp_bitvec_set(vec, 5, true);
 | 
					 | 
				
			||||||
/// sp_bitvec_free(vec);
 | 
					 | 
				
			||||||
/// ```
 | 
					 | 
				
			||||||
pub struct SPBitVec(servicepoint::BitVec);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl From<servicepoint::BitVec> for SPBitVec {
 | 
					 | 
				
			||||||
    fn from(actual: servicepoint::BitVec) -> Self {
 | 
					 | 
				
			||||||
        Self(actual)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl From<SPBitVec> for servicepoint::BitVec {
 | 
					 | 
				
			||||||
    fn from(value: SPBitVec) -> Self {
 | 
					 | 
				
			||||||
        value.0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Clone for SPBitVec {
 | 
					 | 
				
			||||||
    fn clone(&self) -> Self {
 | 
					 | 
				
			||||||
        SPBitVec(self.0.clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Creates a new [SPBitVec] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `size`: size in bits.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: [SPBitVec] with all bits set to false. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `size` is not divisible by 8.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - the returned instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_bitvec_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitvec_new(size: usize) -> NonNull<SPBitVec> {
 | 
					 | 
				
			||||||
    let result = Box::new(SPBitVec(servicepoint::BitVec::repeat(false, size)));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Interpret the data as a series of bits and load then into a new [SPBitVec] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: [SPBitVec] instance containing data. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `data` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # 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_bitvec_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitvec_load(
 | 
					 | 
				
			||||||
    data: *const u8,
 | 
					 | 
				
			||||||
    data_length: usize,
 | 
					 | 
				
			||||||
) -> NonNull<SPBitVec> {
 | 
					 | 
				
			||||||
    assert!(!data.is_null());
 | 
					 | 
				
			||||||
    let data = std::slice::from_raw_parts(data, data_length);
 | 
					 | 
				
			||||||
    let result = Box::new(SPBitVec(servicepoint::BitVec::from_slice(data)));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Clones a [SPBitVec].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: new [SPBitVec] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bit_vec` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid [SPBitVec]
 | 
					 | 
				
			||||||
/// - `bit_vec` is not written to concurrently
 | 
					 | 
				
			||||||
/// - the returned instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_bitvec_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitvec_clone(
 | 
					 | 
				
			||||||
    bit_vec: *const SPBitVec,
 | 
					 | 
				
			||||||
) -> NonNull<SPBitVec> {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    let result = Box::new((*bit_vec).clone());
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Deallocates a [SPBitVec].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `but_vec` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid [SPBitVec]
 | 
					 | 
				
			||||||
/// - `bit_vec` is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - `bit_vec` was not passed to another consuming function, e.g. to create a [SPCommand]
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// [SPCommand]: [crate::SPCommand]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    _ = Box::from_raw(bit_vec);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the value of a bit from the [SPBitVec].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec`: instance to read from
 | 
					 | 
				
			||||||
/// - `index`: the bit index to read
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: value of the bit
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bit_vec` is NULL
 | 
					 | 
				
			||||||
/// - when accessing `index` out of bounds
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid [SPBitVec]
 | 
					 | 
				
			||||||
/// - `bit_vec` is not written to concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitvec_get(
 | 
					 | 
				
			||||||
    bit_vec: *const SPBitVec,
 | 
					 | 
				
			||||||
    index: usize,
 | 
					 | 
				
			||||||
) -> bool {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    *(*bit_vec).0.get(index).unwrap()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sets the value of a bit in the [SPBitVec].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec`: instance to write to
 | 
					 | 
				
			||||||
/// - `index`: the bit index to edit
 | 
					 | 
				
			||||||
/// - `value`: the value to set the bit to
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bit_vec` is NULL
 | 
					 | 
				
			||||||
/// - when accessing `index` out of bounds
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid [SPBitVec]
 | 
					 | 
				
			||||||
/// - `bit_vec` is not written to or read from concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitvec_set(
 | 
					 | 
				
			||||||
    bit_vec: *mut SPBitVec,
 | 
					 | 
				
			||||||
    index: usize,
 | 
					 | 
				
			||||||
    value: bool,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    (*bit_vec).0.set(index, value)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sets the value of all bits in the [SPBitVec].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec`: instance to write to
 | 
					 | 
				
			||||||
/// - `value`: the value to set all bits to
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bit_vec` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid [SPBitVec]
 | 
					 | 
				
			||||||
/// - `bit_vec` is not written to or read from concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitvec_fill(bit_vec: *mut SPBitVec, value: bool) {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    (*bit_vec).0.fill(value)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the length of the [SPBitVec] in bits.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec`: instance to write to
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bit_vec` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid [SPBitVec]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitvec_len(bit_vec: *const SPBitVec) -> usize {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    (*bit_vec).0.len()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Returns true if length is 0.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec`: instance to write to
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bit_vec` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid [SPBitVec]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitvec_is_empty(bit_vec: *const SPBitVec) -> bool {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    (*bit_vec).0.is_empty()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets an unsafe reference to the data of the [SPBitVec] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec`: instance to write to
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bit_vec` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// ## Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid [SPBitVec]
 | 
					 | 
				
			||||||
/// - the returned memory range is never accessed after the passed [SPBitVec] has been freed
 | 
					 | 
				
			||||||
/// - the returned memory range is never accessed concurrently, either via the [SPBitVec] or directly
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_bitvec_unsafe_data_ref(
 | 
					 | 
				
			||||||
    bit_vec: *mut SPBitVec,
 | 
					 | 
				
			||||||
) -> SPByteSlice {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    let data = (*bit_vec).0.as_raw_mut_slice();
 | 
					 | 
				
			||||||
    SPByteSlice {
 | 
					 | 
				
			||||||
        start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
 | 
					 | 
				
			||||||
        length: data.len(),
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,322 +0,0 @@
 | 
				
			||||||
//! C functions for interacting with [SPBrightnessGrid]s
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! prefix `sp_brightness_grid_`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::SPByteSlice;
 | 
					 | 
				
			||||||
use servicepoint::{DataRef, Grid};
 | 
					 | 
				
			||||||
use std::convert::Into;
 | 
					 | 
				
			||||||
use std::intrinsics::transmute;
 | 
					 | 
				
			||||||
use std::ptr::NonNull;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// see [servicepoint::Brightness::MIN]
 | 
					 | 
				
			||||||
pub const SP_BRIGHTNESS_MIN: u8 = 0;
 | 
					 | 
				
			||||||
/// see [servicepoint::Brightness::MAX]
 | 
					 | 
				
			||||||
pub const SP_BRIGHTNESS_MAX: u8 = 11;
 | 
					 | 
				
			||||||
/// Count of possible brightness values
 | 
					 | 
				
			||||||
pub const SP_BRIGHTNESS_LEVELS: u8 = 12;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A grid containing brightness values.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Examples
 | 
					 | 
				
			||||||
/// ```C
 | 
					 | 
				
			||||||
/// SPConnection connection = sp_connection_open("127.0.0.1:2342");
 | 
					 | 
				
			||||||
/// if (connection == NULL)
 | 
					 | 
				
			||||||
///     return 1;
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// SPBrightnessGrid grid = sp_brightness_grid_new(2, 2);
 | 
					 | 
				
			||||||
/// sp_brightness_grid_set(grid, 0, 0, 0);
 | 
					 | 
				
			||||||
/// sp_brightness_grid_set(grid, 1, 1, 10);
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// SPCommand command = sp_command_char_brightness(grid);
 | 
					 | 
				
			||||||
/// sp_connection_free(connection);
 | 
					 | 
				
			||||||
/// ```
 | 
					 | 
				
			||||||
#[derive(Clone)]
 | 
					 | 
				
			||||||
pub struct SPBrightnessGrid(pub(crate) servicepoint::BrightnessGrid);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Creates a new [SPBrightnessGrid] with the specified dimensions.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: [SPBrightnessGrid] initialized to 0. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # 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_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_brightness_grid_new(
 | 
					 | 
				
			||||||
    width: usize,
 | 
					 | 
				
			||||||
    height: usize,
 | 
					 | 
				
			||||||
) -> NonNull<SPBrightnessGrid> {
 | 
					 | 
				
			||||||
    let result = Box::new(SPBrightnessGrid(servicepoint::BrightnessGrid::new(
 | 
					 | 
				
			||||||
        width, height,
 | 
					 | 
				
			||||||
    )));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Loads a [SPBrightnessGrid] with the specified dimensions from the provided data.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: new [SPBrightnessGrid] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `data` is NULL
 | 
					 | 
				
			||||||
/// - when the provided `data_length` does not match `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_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_brightness_grid_load(
 | 
					 | 
				
			||||||
    width: usize,
 | 
					 | 
				
			||||||
    height: usize,
 | 
					 | 
				
			||||||
    data: *const u8,
 | 
					 | 
				
			||||||
    data_length: usize,
 | 
					 | 
				
			||||||
) -> NonNull<SPBrightnessGrid> {
 | 
					 | 
				
			||||||
    assert!(!data.is_null());
 | 
					 | 
				
			||||||
    let data = std::slice::from_raw_parts(data, data_length);
 | 
					 | 
				
			||||||
    let grid = servicepoint::ByteGrid::load(width, height, data);
 | 
					 | 
				
			||||||
    let grid = servicepoint::BrightnessGrid::try_from(grid)
 | 
					 | 
				
			||||||
        .expect("invalid brightness value");
 | 
					 | 
				
			||||||
    let result = Box::new(SPBrightnessGrid(grid));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Clones a [SPBrightnessGrid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid`: instance to read from
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: new [SPBrightnessGrid] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `brightness_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
 | 
					 | 
				
			||||||
/// - `brightness_grid` is not written to concurrently
 | 
					 | 
				
			||||||
/// - the returned instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_brightness_grid_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_brightness_grid_clone(
 | 
					 | 
				
			||||||
    brightness_grid: *const SPBrightnessGrid,
 | 
					 | 
				
			||||||
) -> NonNull<SPBrightnessGrid> {
 | 
					 | 
				
			||||||
    assert!(!brightness_grid.is_null());
 | 
					 | 
				
			||||||
    let result = Box::new((*brightness_grid).clone());
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Deallocates a [SPBrightnessGrid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid`: instance to read from
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `brightness_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
 | 
					 | 
				
			||||||
/// - `brightness_grid` is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - `brightness_grid` was not passed to another consuming function, e.g. to create a [SPCommand]
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// [SPCommand]: [crate::SPCommand]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_brightness_grid_free(
 | 
					 | 
				
			||||||
    brightness_grid: *mut SPBrightnessGrid,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    assert!(!brightness_grid.is_null());
 | 
					 | 
				
			||||||
    _ = Box::from_raw(brightness_grid);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the current value at the specified position.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid`: instance to read from
 | 
					 | 
				
			||||||
/// - `x` and `y`: position of the cell to read
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: value at position
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `brightness_grid` is NULL
 | 
					 | 
				
			||||||
/// - When accessing `x` or `y` out of bounds.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
 | 
					 | 
				
			||||||
/// - `brightness_grid` is not written to concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_brightness_grid_get(
 | 
					 | 
				
			||||||
    brightness_grid: *const SPBrightnessGrid,
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
) -> u8 {
 | 
					 | 
				
			||||||
    assert!(!brightness_grid.is_null());
 | 
					 | 
				
			||||||
    (*brightness_grid).0.get(x, y).into()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sets the value of the specified position in the [SPBrightnessGrid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid`: instance to write to
 | 
					 | 
				
			||||||
/// - `x` and `y`: position of the cell
 | 
					 | 
				
			||||||
/// - `value`: the value to write to the cell
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: old value of the cell
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `brightness_grid` is NULL
 | 
					 | 
				
			||||||
/// - When accessing `x` or `y` out of bounds.
 | 
					 | 
				
			||||||
/// - When providing an invalid brightness value
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
 | 
					 | 
				
			||||||
/// - `brightness_grid` is not written to or read from concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_brightness_grid_set(
 | 
					 | 
				
			||||||
    brightness_grid: *mut SPBrightnessGrid,
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
    value: u8,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    assert!(!brightness_grid.is_null());
 | 
					 | 
				
			||||||
    let brightness = servicepoint::Brightness::try_from(value)
 | 
					 | 
				
			||||||
        .expect("invalid brightness value");
 | 
					 | 
				
			||||||
    (*brightness_grid).0.set(x, y, brightness);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sets the value of all cells in the [SPBrightnessGrid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid`: instance to write to
 | 
					 | 
				
			||||||
/// - `value`: the value to set all cells to
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `brightness_grid` is NULL
 | 
					 | 
				
			||||||
/// - When providing an invalid brightness value
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
 | 
					 | 
				
			||||||
/// - `brightness_grid` is not written to or read from concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_brightness_grid_fill(
 | 
					 | 
				
			||||||
    brightness_grid: *mut SPBrightnessGrid,
 | 
					 | 
				
			||||||
    value: u8,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    assert!(!brightness_grid.is_null());
 | 
					 | 
				
			||||||
    let brightness = servicepoint::Brightness::try_from(value)
 | 
					 | 
				
			||||||
        .expect("invalid brightness value");
 | 
					 | 
				
			||||||
    (*brightness_grid).0.fill(brightness);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the width of the [SPBrightnessGrid] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid`: instance to read from
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: width
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `brightness_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_brightness_grid_width(
 | 
					 | 
				
			||||||
    brightness_grid: *const SPBrightnessGrid,
 | 
					 | 
				
			||||||
) -> usize {
 | 
					 | 
				
			||||||
    assert!(!brightness_grid.is_null());
 | 
					 | 
				
			||||||
    (*brightness_grid).0.width()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the height of the [SPBrightnessGrid] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid`: instance to read from
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: height
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `brightness_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_brightness_grid_height(
 | 
					 | 
				
			||||||
    brightness_grid: *const SPBrightnessGrid,
 | 
					 | 
				
			||||||
) -> usize {
 | 
					 | 
				
			||||||
    assert!(!brightness_grid.is_null());
 | 
					 | 
				
			||||||
    (*brightness_grid).0.height()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets an unsafe reference to the data of the [SPBrightnessGrid] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid`: instance to read from
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: slice of bytes underlying the `brightness_grid`.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `brightness_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
 | 
					 | 
				
			||||||
/// - the returned memory range is never accessed after the passed [SPBrightnessGrid] has been freed
 | 
					 | 
				
			||||||
/// - the returned memory range is never accessed concurrently, either via the [SPBrightnessGrid] or directly
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref(
 | 
					 | 
				
			||||||
    brightness_grid: *mut SPBrightnessGrid,
 | 
					 | 
				
			||||||
) -> SPByteSlice {
 | 
					 | 
				
			||||||
    assert!(!brightness_grid.is_null());
 | 
					 | 
				
			||||||
    assert_eq!(core::mem::size_of::<servicepoint::Brightness>(), 1);
 | 
					 | 
				
			||||||
    let data = (*brightness_grid).0.data_ref_mut();
 | 
					 | 
				
			||||||
    // this assumes more about the memory layout than rust guarantees. yikes!
 | 
					 | 
				
			||||||
    let data: &mut [u8] = transmute(data);
 | 
					 | 
				
			||||||
    SPByteSlice {
 | 
					 | 
				
			||||||
        start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
 | 
					 | 
				
			||||||
        length: data.len(),
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,24 +0,0 @@
 | 
				
			||||||
//! FFI slice helper
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use std::ptr::NonNull;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
/// Represents a span of memory (`&mut [u8]` ) as a struct usable by C code.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// You should not create an instance of this type in your C code.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - accesses to the memory pointed to with `start` is never accessed outside `length`
 | 
					 | 
				
			||||||
/// - the lifetime of the `CByteSlice` does not outlive the memory it points to, as described in
 | 
					 | 
				
			||||||
///   the function returning this type.
 | 
					 | 
				
			||||||
/// - an instance of this created from C is never passed to a consuming function, as the rust code
 | 
					 | 
				
			||||||
///   will try to free the memory of a potentially separate allocator.
 | 
					 | 
				
			||||||
pub struct SPByteSlice {
 | 
					 | 
				
			||||||
    /// The start address of the memory
 | 
					 | 
				
			||||||
    pub start: NonNull<u8>,
 | 
					 | 
				
			||||||
    /// The amount of memory in bytes
 | 
					 | 
				
			||||||
    pub length: usize,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,263 +0,0 @@
 | 
				
			||||||
//! C functions for interacting with [SPCharGrid]s
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! prefix `sp_char_grid_`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use servicepoint::Grid;
 | 
					 | 
				
			||||||
use std::ptr::NonNull;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A C-wrapper for grid containing UTF-8 characters.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// As the rust [char] type is not FFI-safe, characters are passed in their UTF-32 form as 32bit unsigned integers.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The encoding is enforced in most cases by the rust standard library
 | 
					 | 
				
			||||||
/// and will panic when provided with illegal characters.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Examples
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// ```C
 | 
					 | 
				
			||||||
/// CharGrid grid = sp_char_grid_new(4, 3);
 | 
					 | 
				
			||||||
/// sp_char_grid_fill(grid, '?');
 | 
					 | 
				
			||||||
/// sp_char_grid_set(grid, 0, 0, '!');
 | 
					 | 
				
			||||||
/// sp_char_grid_free(grid);
 | 
					 | 
				
			||||||
/// ```
 | 
					 | 
				
			||||||
pub struct SPCharGrid(pub(crate) servicepoint::CharGrid);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Clone for SPCharGrid {
 | 
					 | 
				
			||||||
    fn clone(&self) -> Self {
 | 
					 | 
				
			||||||
        SPCharGrid(self.0.clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Creates a new [SPCharGrid] with the specified dimensions.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: [SPCharGrid] initialized to 0. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # 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_char_grid_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_char_grid_new(
 | 
					 | 
				
			||||||
    width: usize,
 | 
					 | 
				
			||||||
    height: usize,
 | 
					 | 
				
			||||||
) -> NonNull<SPCharGrid> {
 | 
					 | 
				
			||||||
    let result =
 | 
					 | 
				
			||||||
        Box::new(SPCharGrid(servicepoint::CharGrid::new(width, height)));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Loads a [SPCharGrid] with the specified dimensions from the provided data.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `data` is NULL
 | 
					 | 
				
			||||||
/// - when the provided `data_length` does not match `height` and `width`
 | 
					 | 
				
			||||||
/// - when `data` is not valid UTF-8
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `data` points to a valid memory location of at least `data_length`
 | 
					 | 
				
			||||||
///   bytes in size.
 | 
					 | 
				
			||||||
/// - the returned instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_char_grid_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_char_grid_load(
 | 
					 | 
				
			||||||
    width: usize,
 | 
					 | 
				
			||||||
    height: usize,
 | 
					 | 
				
			||||||
    data: *const u8,
 | 
					 | 
				
			||||||
    data_length: usize,
 | 
					 | 
				
			||||||
) -> NonNull<SPCharGrid> {
 | 
					 | 
				
			||||||
    assert!(data.is_null());
 | 
					 | 
				
			||||||
    let data = std::slice::from_raw_parts(data, data_length);
 | 
					 | 
				
			||||||
    let result = Box::new(SPCharGrid(
 | 
					 | 
				
			||||||
        servicepoint::CharGrid::load_utf8(width, height, data.to_vec())
 | 
					 | 
				
			||||||
            .unwrap(),
 | 
					 | 
				
			||||||
    ));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Clones a [SPCharGrid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `char_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid` points to a valid [SPCharGrid]
 | 
					 | 
				
			||||||
/// - `char_grid` is not written to concurrently
 | 
					 | 
				
			||||||
/// - the returned instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_char_grid_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_char_grid_clone(
 | 
					 | 
				
			||||||
    char_grid: *const SPCharGrid,
 | 
					 | 
				
			||||||
) -> NonNull<SPCharGrid> {
 | 
					 | 
				
			||||||
    assert!(!char_grid.is_null());
 | 
					 | 
				
			||||||
    let result = Box::new((*char_grid).clone());
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Deallocates a [SPCharGrid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `char_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid` points to a valid [SPCharGrid]
 | 
					 | 
				
			||||||
/// - `char_grid` is not used concurrently or after char_grid call
 | 
					 | 
				
			||||||
/// - `char_grid` was not passed to another consuming function, e.g. to create a [SPCommand]
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// [SPCommand]: [crate::SPCommand]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_char_grid_free(char_grid: *mut SPCharGrid) {
 | 
					 | 
				
			||||||
    assert!(!char_grid.is_null());
 | 
					 | 
				
			||||||
    _ = Box::from_raw(char_grid);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the current value at the specified position.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid`: instance to read from
 | 
					 | 
				
			||||||
/// - `x` and `y`: position of the cell to read
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `char_grid` is NULL
 | 
					 | 
				
			||||||
/// - when accessing `x` or `y` out of bounds
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid` points to a valid [SPCharGrid]
 | 
					 | 
				
			||||||
/// - `char_grid` is not written to concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_char_grid_get(
 | 
					 | 
				
			||||||
    char_grid: *const SPCharGrid,
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
) -> u32 {
 | 
					 | 
				
			||||||
    assert!(!char_grid.is_null());
 | 
					 | 
				
			||||||
    (*char_grid).0.get(x, y) as u32
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sets the value of the specified position in the [SPCharGrid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid`: instance to write to
 | 
					 | 
				
			||||||
/// - `x` and `y`: position of the cell
 | 
					 | 
				
			||||||
/// - `value`: the value to write to the cell
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: old value of the cell
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `char_grid` is NULL
 | 
					 | 
				
			||||||
/// - when accessing `x` or `y` out of bounds
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid` points to a valid [SPBitVec]
 | 
					 | 
				
			||||||
/// - `char_grid` is not written to or read from concurrently
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// [SPBitVec]: [crate::SPBitVec]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_char_grid_set(
 | 
					 | 
				
			||||||
    char_grid: *mut SPCharGrid,
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
    value: u32,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    assert!(!char_grid.is_null());
 | 
					 | 
				
			||||||
    (*char_grid).0.set(x, y, char::from_u32(value).unwrap());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sets the value of all cells in the [SPCharGrid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid`: instance to write to
 | 
					 | 
				
			||||||
/// - `value`: the value to set all cells to
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `char_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid` points to a valid [SPCharGrid]
 | 
					 | 
				
			||||||
/// - `char_grid` is not written to or read from concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_char_grid_fill(
 | 
					 | 
				
			||||||
    char_grid: *mut SPCharGrid,
 | 
					 | 
				
			||||||
    value: u32,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    assert!(!char_grid.is_null());
 | 
					 | 
				
			||||||
    (*char_grid).0.fill(char::from_u32(value).unwrap());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the width of the [SPCharGrid] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid`: instance to read from
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `char_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid` points to a valid [SPCharGrid]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_char_grid_width(
 | 
					 | 
				
			||||||
    char_grid: *const SPCharGrid,
 | 
					 | 
				
			||||||
) -> usize {
 | 
					 | 
				
			||||||
    assert!(!char_grid.is_null());
 | 
					 | 
				
			||||||
    (*char_grid).0.width()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the height of the [SPCharGrid] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid`: instance to read from
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `char_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `char_grid` points to a valid [SPCharGrid]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_char_grid_height(
 | 
					 | 
				
			||||||
    char_grid: *const SPCharGrid,
 | 
					 | 
				
			||||||
) -> usize {
 | 
					 | 
				
			||||||
    assert!(!char_grid.is_null());
 | 
					 | 
				
			||||||
    (*char_grid).0.height()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,498 +0,0 @@
 | 
				
			||||||
//! C functions for interacting with [SPCommand]s
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! prefix `sp_command_`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use std::ptr::{null_mut, NonNull};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::{
 | 
					 | 
				
			||||||
    SPBitVec, SPBitmap, SPBrightnessGrid, SPCharGrid, SPCompressionCode,
 | 
					 | 
				
			||||||
    SPCp437Grid, SPPacket,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A low-level display command.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// This struct and associated functions implement the UDP protocol for the display.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// To send a [SPCommand], use a [SPConnection].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Examples
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// ```C
 | 
					 | 
				
			||||||
/// sp_connection_send_command(connection, sp_command_clear());
 | 
					 | 
				
			||||||
/// sp_connection_send_command(connection, sp_command_brightness(5));
 | 
					 | 
				
			||||||
/// ```
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// [SPConnection]: [crate::SPConnection]
 | 
					 | 
				
			||||||
pub struct SPCommand(pub(crate) servicepoint::Command);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Clone for SPCommand {
 | 
					 | 
				
			||||||
    fn clone(&self) -> Self {
 | 
					 | 
				
			||||||
        SPCommand(self.0.clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Tries to turn a [SPPacket] into a [SPCommand].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The packet is deallocated in the process.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: pointer to new [SPCommand] instance or NULL if parsing failed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `packet` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - [SPPacket] points to a valid instance of [SPPacket]
 | 
					 | 
				
			||||||
/// - [SPPacket] is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - the result is checked for NULL
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_try_from_packet(
 | 
					 | 
				
			||||||
    packet: *mut SPPacket,
 | 
					 | 
				
			||||||
) -> *mut SPCommand {
 | 
					 | 
				
			||||||
    let packet = *Box::from_raw(packet);
 | 
					 | 
				
			||||||
    match servicepoint::Command::try_from(packet.0) {
 | 
					 | 
				
			||||||
        Err(_) => null_mut(),
 | 
					 | 
				
			||||||
        Ok(command) => Box::into_raw(Box::new(SPCommand(command))),
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Clones a [SPCommand] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: new [SPCommand] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `command` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `command` points to a valid instance of [SPCommand]
 | 
					 | 
				
			||||||
/// - `command` is not written to concurrently
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_clone(
 | 
					 | 
				
			||||||
    command: *const SPCommand,
 | 
					 | 
				
			||||||
) -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    assert!(!command.is_null());
 | 
					 | 
				
			||||||
    let result = Box::new((*command).clone());
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Set all pixels to the off state.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Does not affect brightness.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::Clear] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Examples
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// ```C
 | 
					 | 
				
			||||||
/// sp_connection_send_command(connection, sp_command_clear());
 | 
					 | 
				
			||||||
/// ```
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_clear() -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    let result = Box::new(SPCommand(servicepoint::Command::Clear));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Kills the udp daemon on the display, which usually results in a restart.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Please do not send this in your normal program flow.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::HardReset] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    let result = Box::new(SPCommand(servicepoint::Command::HardReset));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A yet-to-be-tested command.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::FadeOut] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_fade_out() -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    let result = Box::new(SPCommand(servicepoint::Command::FadeOut));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Set the brightness of all tiles to the same value.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::Brightness] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - When the provided brightness value is out of range (0-11).
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_brightness(
 | 
					 | 
				
			||||||
    brightness: u8,
 | 
					 | 
				
			||||||
) -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    let brightness = servicepoint::Brightness::try_from(brightness)
 | 
					 | 
				
			||||||
        .expect("invalid brightness");
 | 
					 | 
				
			||||||
    let result =
 | 
					 | 
				
			||||||
        Box::new(SPCommand(servicepoint::Command::Brightness(brightness)));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Set the brightness of individual tiles in a rectangular area of the display.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The passed [SPBrightnessGrid] gets consumed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::CharBrightness] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `grid` points to a valid instance of [SPBrightnessGrid]
 | 
					 | 
				
			||||||
/// - `grid` is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_char_brightness(
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
    grid: *mut SPBrightnessGrid,
 | 
					 | 
				
			||||||
) -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    assert!(!grid.is_null());
 | 
					 | 
				
			||||||
    let byte_grid = *Box::from_raw(grid);
 | 
					 | 
				
			||||||
    let result = Box::new(SPCommand(servicepoint::Command::CharBrightness(
 | 
					 | 
				
			||||||
        servicepoint::Origin::new(x, y),
 | 
					 | 
				
			||||||
        byte_grid.0,
 | 
					 | 
				
			||||||
    )));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// 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 [SPBitVec] is always uncompressed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The passed [SPBitVec] gets consumed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::BitmapLinear] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bit_vec` is null
 | 
					 | 
				
			||||||
/// - when `compression_code` is not a valid value
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid instance of [SPBitVec]
 | 
					 | 
				
			||||||
/// - `bit_vec` is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - `compression` matches one of the allowed enum values
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_bitmap_linear(
 | 
					 | 
				
			||||||
    offset: usize,
 | 
					 | 
				
			||||||
    bit_vec: *mut SPBitVec,
 | 
					 | 
				
			||||||
    compression: SPCompressionCode,
 | 
					 | 
				
			||||||
) -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    let bit_vec = *Box::from_raw(bit_vec);
 | 
					 | 
				
			||||||
    let result = Box::new(SPCommand(servicepoint::Command::BitmapLinear(
 | 
					 | 
				
			||||||
        offset,
 | 
					 | 
				
			||||||
        bit_vec.into(),
 | 
					 | 
				
			||||||
        compression.try_into().expect("invalid compression code"),
 | 
					 | 
				
			||||||
    )));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Set pixel data according to an and-mask starting at the offset.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
 | 
					 | 
				
			||||||
/// once the starting row is full, overwriting will continue on column 0.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The contained [SPBitVec] is always uncompressed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The passed [SPBitVec] gets consumed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::BitmapLinearAnd] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bit_vec` is null
 | 
					 | 
				
			||||||
/// - when `compression_code` is not a valid value
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid instance of [SPBitVec]
 | 
					 | 
				
			||||||
/// - `bit_vec` is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - `compression` matches one of the allowed enum values
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_bitmap_linear_and(
 | 
					 | 
				
			||||||
    offset: usize,
 | 
					 | 
				
			||||||
    bit_vec: *mut SPBitVec,
 | 
					 | 
				
			||||||
    compression: SPCompressionCode,
 | 
					 | 
				
			||||||
) -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    let bit_vec = *Box::from_raw(bit_vec);
 | 
					 | 
				
			||||||
    let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearAnd(
 | 
					 | 
				
			||||||
        offset,
 | 
					 | 
				
			||||||
        bit_vec.into(),
 | 
					 | 
				
			||||||
        compression.try_into().expect("invalid compression code"),
 | 
					 | 
				
			||||||
    )));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Set pixel data according to an or-mask starting at the offset.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
 | 
					 | 
				
			||||||
/// once the starting row is full, overwriting will continue on column 0.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The contained [SPBitVec] is always uncompressed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The passed [SPBitVec] gets consumed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::BitmapLinearOr] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bit_vec` is null
 | 
					 | 
				
			||||||
/// - when `compression_code` is not a valid value
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid instance of [SPBitVec]
 | 
					 | 
				
			||||||
/// - `bit_vec` is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - `compression` matches one of the allowed enum values
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_bitmap_linear_or(
 | 
					 | 
				
			||||||
    offset: usize,
 | 
					 | 
				
			||||||
    bit_vec: *mut SPBitVec,
 | 
					 | 
				
			||||||
    compression: SPCompressionCode,
 | 
					 | 
				
			||||||
) -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    let bit_vec = *Box::from_raw(bit_vec);
 | 
					 | 
				
			||||||
    let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearOr(
 | 
					 | 
				
			||||||
        offset,
 | 
					 | 
				
			||||||
        bit_vec.into(),
 | 
					 | 
				
			||||||
        compression.try_into().expect("invalid compression code"),
 | 
					 | 
				
			||||||
    )));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Set pixel data according to a xor-mask starting at the offset.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
 | 
					 | 
				
			||||||
/// once the starting row is full, overwriting will continue on column 0.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The contained [SPBitVec] is always uncompressed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The passed [SPBitVec] gets consumed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::BitmapLinearXor] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bit_vec` is null
 | 
					 | 
				
			||||||
/// - when `compression_code` is not a valid value
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bit_vec` points to a valid instance of [SPBitVec]
 | 
					 | 
				
			||||||
/// - `bit_vec` is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - `compression` matches one of the allowed enum values
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
 | 
					 | 
				
			||||||
    offset: usize,
 | 
					 | 
				
			||||||
    bit_vec: *mut SPBitVec,
 | 
					 | 
				
			||||||
    compression: SPCompressionCode,
 | 
					 | 
				
			||||||
) -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    assert!(!bit_vec.is_null());
 | 
					 | 
				
			||||||
    let bit_vec = *Box::from_raw(bit_vec);
 | 
					 | 
				
			||||||
    let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearXor(
 | 
					 | 
				
			||||||
        offset,
 | 
					 | 
				
			||||||
        bit_vec.into(),
 | 
					 | 
				
			||||||
        compression.try_into().expect("invalid compression code"),
 | 
					 | 
				
			||||||
    )));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Show codepage 437 encoded text on the screen.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The passed [SPCp437Grid] gets consumed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::Cp437Data] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `grid` is null
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `grid` points to a valid instance of [SPCp437Grid]
 | 
					 | 
				
			||||||
/// - `grid` is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_cp437_data(
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
    grid: *mut SPCp437Grid,
 | 
					 | 
				
			||||||
) -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    assert!(!grid.is_null());
 | 
					 | 
				
			||||||
    let grid = *Box::from_raw(grid);
 | 
					 | 
				
			||||||
    let result = Box::new(SPCommand(servicepoint::Command::Cp437Data(
 | 
					 | 
				
			||||||
        servicepoint::Origin::new(x, y),
 | 
					 | 
				
			||||||
        grid.0,
 | 
					 | 
				
			||||||
    )));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Show UTF-8 encoded text on the screen.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The passed [SPCharGrid] gets consumed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::Utf8Data] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `grid` is null
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `grid` points to a valid instance of [SPCharGrid]
 | 
					 | 
				
			||||||
/// - `grid` is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_utf8_data(
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
    grid: *mut SPCharGrid,
 | 
					 | 
				
			||||||
) -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    assert!(!grid.is_null());
 | 
					 | 
				
			||||||
    let grid = *Box::from_raw(grid);
 | 
					 | 
				
			||||||
    let result = Box::new(SPCommand(servicepoint::Command::Utf8Data(
 | 
					 | 
				
			||||||
        servicepoint::Origin::new(x, y),
 | 
					 | 
				
			||||||
        grid.0,
 | 
					 | 
				
			||||||
    )));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sets a window of pixels to the specified values.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The passed [SPBitmap] gets consumed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Returns: a new [servicepoint::Command::BitmapLinearWin] instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `bitmap` is null
 | 
					 | 
				
			||||||
/// - when `compression_code` is not a valid value
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `bitmap` points to a valid instance of [SPBitmap]
 | 
					 | 
				
			||||||
/// - `bitmap` is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - `compression` matches one of the allowed enum values
 | 
					 | 
				
			||||||
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_command_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_bitmap_linear_win(
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
    bitmap: *mut SPBitmap,
 | 
					 | 
				
			||||||
    compression_code: SPCompressionCode,
 | 
					 | 
				
			||||||
) -> NonNull<SPCommand> {
 | 
					 | 
				
			||||||
    assert!(!bitmap.is_null());
 | 
					 | 
				
			||||||
    let byte_grid = (*Box::from_raw(bitmap)).0;
 | 
					 | 
				
			||||||
    let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearWin(
 | 
					 | 
				
			||||||
        servicepoint::Origin::new(x, y),
 | 
					 | 
				
			||||||
        byte_grid,
 | 
					 | 
				
			||||||
        compression_code
 | 
					 | 
				
			||||||
            .try_into()
 | 
					 | 
				
			||||||
            .expect("invalid compression code"),
 | 
					 | 
				
			||||||
    )));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Deallocates a [SPCommand].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Examples
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// ```C
 | 
					 | 
				
			||||||
/// SPCommand c = sp_command_clear();
 | 
					 | 
				
			||||||
/// sp_command_free(c);
 | 
					 | 
				
			||||||
/// ```
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `command` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `command` points to a valid [SPCommand]
 | 
					 | 
				
			||||||
/// - `command` is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - `command` was not passed to another consuming function, e.g. to create a [SPPacket]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_command_free(command: *mut SPCommand) {
 | 
					 | 
				
			||||||
    assert!(!command.is_null());
 | 
					 | 
				
			||||||
    _ = Box::from_raw(command);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,139 +0,0 @@
 | 
				
			||||||
//! C functions for interacting with [SPConnection]s
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! prefix `sp_connection_`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use std::ffi::{c_char, CStr};
 | 
					 | 
				
			||||||
use std::ptr::{null_mut, NonNull};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::{SPCommand, SPPacket};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A connection to the display.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Examples
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// ```C
 | 
					 | 
				
			||||||
/// CConnection connection = sp_connection_open("172.23.42.29:2342");
 | 
					 | 
				
			||||||
/// if (connection != NULL)
 | 
					 | 
				
			||||||
///     sp_connection_send_command(connection, sp_command_clear());
 | 
					 | 
				
			||||||
/// ```
 | 
					 | 
				
			||||||
pub struct SPConnection(pub(crate) servicepoint::Connection);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Creates a new instance of [SPConnection].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: NULL if connection fails, or connected instance
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `host` is null or an invalid host
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # 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_connection_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_connection_open(
 | 
					 | 
				
			||||||
    host: *const c_char,
 | 
					 | 
				
			||||||
) -> *mut SPConnection {
 | 
					 | 
				
			||||||
    assert!(!host.is_null());
 | 
					 | 
				
			||||||
    let host = CStr::from_ptr(host).to_str().expect("Bad encoding");
 | 
					 | 
				
			||||||
    let connection = match servicepoint::Connection::open(host) {
 | 
					 | 
				
			||||||
        Err(_) => return null_mut(),
 | 
					 | 
				
			||||||
        Ok(value) => value,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Box::into_raw(Box::new(SPConnection(connection)))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Creates a new instance of [SPConnection] for testing that does not actually send anything.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: a new instance. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # 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_connection_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_connection_fake() -> NonNull<SPConnection> {
 | 
					 | 
				
			||||||
    let result = Box::new(SPConnection(servicepoint::Connection::Fake));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sends a [SPPacket] to the display using the [SPConnection].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The passed `packet` gets consumed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: true in case of success
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `connection` is NULL
 | 
					 | 
				
			||||||
/// - when `packet` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `connection` points to a valid instance of [SPConnection]
 | 
					 | 
				
			||||||
/// - `packet` points to a valid instance of [SPPacket]
 | 
					 | 
				
			||||||
/// - `packet` is not used concurrently or after this call
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_connection_send_packet(
 | 
					 | 
				
			||||||
    connection: *const SPConnection,
 | 
					 | 
				
			||||||
    packet: *mut SPPacket,
 | 
					 | 
				
			||||||
) -> bool {
 | 
					 | 
				
			||||||
    assert!(!connection.is_null());
 | 
					 | 
				
			||||||
    assert!(!packet.is_null());
 | 
					 | 
				
			||||||
    let packet = Box::from_raw(packet);
 | 
					 | 
				
			||||||
    (*connection).0.send((*packet).0).is_ok()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sends a [SPCommand] to the display using the [SPConnection].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The passed `command` gets consumed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: true in case of success
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `connection` is NULL
 | 
					 | 
				
			||||||
/// - when `command` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `connection` points to a valid instance of [SPConnection]
 | 
					 | 
				
			||||||
/// - `command` points to a valid instance of [SPPacket]
 | 
					 | 
				
			||||||
/// - `command` is not used concurrently or after this call
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_connection_send_command(
 | 
					 | 
				
			||||||
    connection: *const SPConnection,
 | 
					 | 
				
			||||||
    command: *mut SPCommand,
 | 
					 | 
				
			||||||
) -> bool {
 | 
					 | 
				
			||||||
    assert!(!connection.is_null());
 | 
					 | 
				
			||||||
    assert!(!command.is_null());
 | 
					 | 
				
			||||||
    let command = (*Box::from_raw(command)).0;
 | 
					 | 
				
			||||||
    (*connection).0.send(command).is_ok()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Closes and deallocates a [SPConnection].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `connection` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `connection` points to a valid [SPConnection]
 | 
					 | 
				
			||||||
/// - `connection` is not used concurrently or after this call
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_connection_free(connection: *mut SPConnection) {
 | 
					 | 
				
			||||||
    assert!(!connection.is_null());
 | 
					 | 
				
			||||||
    _ = Box::from_raw(connection);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,48 +0,0 @@
 | 
				
			||||||
//! re-exported constants for use in C
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use servicepoint::CompressionCode;
 | 
					 | 
				
			||||||
use std::time::Duration;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// size of a single tile in one dimension
 | 
					 | 
				
			||||||
pub const SP_TILE_SIZE: usize = 8;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Display tile count in the x-direction
 | 
					 | 
				
			||||||
pub const SP_TILE_WIDTH: usize = 56;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Display tile count in the y-direction
 | 
					 | 
				
			||||||
pub const SP_TILE_HEIGHT: usize = 20;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Display width in pixels
 | 
					 | 
				
			||||||
pub const SP_PIXEL_WIDTH: usize = SP_TILE_WIDTH * SP_TILE_SIZE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Display height in pixels
 | 
					 | 
				
			||||||
pub const SP_PIXEL_HEIGHT: usize = SP_TILE_HEIGHT * SP_TILE_SIZE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// pixel count on whole screen
 | 
					 | 
				
			||||||
pub const SP_PIXEL_COUNT: usize = SP_PIXEL_WIDTH * SP_PIXEL_HEIGHT;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets.
 | 
					 | 
				
			||||||
pub const SP_FRAME_PACING_MS: u128 = Duration::from_millis(30).as_millis();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Specifies the kind of compression to use.
 | 
					 | 
				
			||||||
#[repr(u16)]
 | 
					 | 
				
			||||||
pub enum SPCompressionCode {
 | 
					 | 
				
			||||||
    /// no compression
 | 
					 | 
				
			||||||
    Uncompressed = 0x0,
 | 
					 | 
				
			||||||
    /// compress using flate2 with zlib header
 | 
					 | 
				
			||||||
    Zlib = 0x677a,
 | 
					 | 
				
			||||||
    /// compress using bzip2
 | 
					 | 
				
			||||||
    Bzip2 = 0x627a,
 | 
					 | 
				
			||||||
    /// compress using lzma
 | 
					 | 
				
			||||||
    Lzma = 0x6c7a,
 | 
					 | 
				
			||||||
    /// compress using Zstandard
 | 
					 | 
				
			||||||
    Zstd = 0x7a73,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl TryFrom<SPCompressionCode> for CompressionCode {
 | 
					 | 
				
			||||||
    type Error = ();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn try_from(value: SPCompressionCode) -> Result<Self, Self::Error> {
 | 
					 | 
				
			||||||
        CompressionCode::try_from(value as u16)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,285 +0,0 @@
 | 
				
			||||||
//! C functions for interacting with [SPCp437Grid]s
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! prefix `sp_cp437_grid_`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::SPByteSlice;
 | 
					 | 
				
			||||||
use servicepoint::{DataRef, Grid};
 | 
					 | 
				
			||||||
use std::ptr::NonNull;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A C-wrapper for grid containing codepage 437 characters.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The encoding is currently not enforced.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Examples
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// ```C
 | 
					 | 
				
			||||||
/// Cp437Grid grid = sp_cp437_grid_new(4, 3);
 | 
					 | 
				
			||||||
/// sp_cp437_grid_fill(grid, '?');
 | 
					 | 
				
			||||||
/// sp_cp437_grid_set(grid, 0, 0, '!');
 | 
					 | 
				
			||||||
/// sp_cp437_grid_free(grid);
 | 
					 | 
				
			||||||
/// ```
 | 
					 | 
				
			||||||
pub struct SPCp437Grid(pub(crate) servicepoint::Cp437Grid);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Clone for SPCp437Grid {
 | 
					 | 
				
			||||||
    fn clone(&self) -> Self {
 | 
					 | 
				
			||||||
        SPCp437Grid(self.0.clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Creates a new [SPCp437Grid] with the specified dimensions.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: [SPCp437Grid] initialized to 0. Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # 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_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_cp437_grid_new(
 | 
					 | 
				
			||||||
    width: usize,
 | 
					 | 
				
			||||||
    height: usize,
 | 
					 | 
				
			||||||
) -> NonNull<SPCp437Grid> {
 | 
					 | 
				
			||||||
    let result =
 | 
					 | 
				
			||||||
        Box::new(SPCp437Grid(servicepoint::Cp437Grid::new(width, height)));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Loads a [SPCp437Grid] with the specified dimensions from the provided data.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `data` is NULL
 | 
					 | 
				
			||||||
/// - when the provided `data_length` does not match `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_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_cp437_grid_load(
 | 
					 | 
				
			||||||
    width: usize,
 | 
					 | 
				
			||||||
    height: usize,
 | 
					 | 
				
			||||||
    data: *const u8,
 | 
					 | 
				
			||||||
    data_length: usize,
 | 
					 | 
				
			||||||
) -> NonNull<SPCp437Grid> {
 | 
					 | 
				
			||||||
    assert!(data.is_null());
 | 
					 | 
				
			||||||
    let data = std::slice::from_raw_parts(data, data_length);
 | 
					 | 
				
			||||||
    let result = Box::new(SPCp437Grid(servicepoint::Cp437Grid::load(
 | 
					 | 
				
			||||||
        width, height, data,
 | 
					 | 
				
			||||||
    )));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Clones a [SPCp437Grid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `cp437_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid` points to a valid [SPCp437Grid]
 | 
					 | 
				
			||||||
/// - `cp437_grid` is not written to concurrently
 | 
					 | 
				
			||||||
/// - the returned instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_cp437_grid_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_cp437_grid_clone(
 | 
					 | 
				
			||||||
    cp437_grid: *const SPCp437Grid,
 | 
					 | 
				
			||||||
) -> NonNull<SPCp437Grid> {
 | 
					 | 
				
			||||||
    assert!(!cp437_grid.is_null());
 | 
					 | 
				
			||||||
    let result = Box::new((*cp437_grid).clone());
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Deallocates a [SPCp437Grid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `cp437_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid` points to a valid [SPCp437Grid]
 | 
					 | 
				
			||||||
/// - `cp437_grid` is not used concurrently or after cp437_grid call
 | 
					 | 
				
			||||||
/// - `cp437_grid` was not passed to another consuming function, e.g. to create a [SPCommand]
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// [SPCommand]: [crate::SPCommand]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) {
 | 
					 | 
				
			||||||
    assert!(!cp437_grid.is_null());
 | 
					 | 
				
			||||||
    _ = Box::from_raw(cp437_grid);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the current value at the specified position.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid`: instance to read from
 | 
					 | 
				
			||||||
/// - `x` and `y`: position of the cell to read
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `cp437_grid` is NULL
 | 
					 | 
				
			||||||
/// - when accessing `x` or `y` out of bounds
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid` points to a valid [SPCp437Grid]
 | 
					 | 
				
			||||||
/// - `cp437_grid` is not written to concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_cp437_grid_get(
 | 
					 | 
				
			||||||
    cp437_grid: *const SPCp437Grid,
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
) -> u8 {
 | 
					 | 
				
			||||||
    assert!(!cp437_grid.is_null());
 | 
					 | 
				
			||||||
    (*cp437_grid).0.get(x, y)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sets the value of the specified position in the [SPCp437Grid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid`: instance to write to
 | 
					 | 
				
			||||||
/// - `x` and `y`: position of the cell
 | 
					 | 
				
			||||||
/// - `value`: the value to write to the cell
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: old value of the cell
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `cp437_grid` is NULL
 | 
					 | 
				
			||||||
/// - when accessing `x` or `y` out of bounds
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid` points to a valid [SPBitVec]
 | 
					 | 
				
			||||||
/// - `cp437_grid` is not written to or read from concurrently
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// [SPBitVec]: [crate::SPBitVec]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_cp437_grid_set(
 | 
					 | 
				
			||||||
    cp437_grid: *mut SPCp437Grid,
 | 
					 | 
				
			||||||
    x: usize,
 | 
					 | 
				
			||||||
    y: usize,
 | 
					 | 
				
			||||||
    value: u8,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    assert!(!cp437_grid.is_null());
 | 
					 | 
				
			||||||
    (*cp437_grid).0.set(x, y, value);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Sets the value of all cells in the [SPCp437Grid].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid`: instance to write to
 | 
					 | 
				
			||||||
/// - `value`: the value to set all cells to
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `cp437_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid` points to a valid [SPCp437Grid]
 | 
					 | 
				
			||||||
/// - `cp437_grid` is not written to or read from concurrently
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_cp437_grid_fill(
 | 
					 | 
				
			||||||
    cp437_grid: *mut SPCp437Grid,
 | 
					 | 
				
			||||||
    value: u8,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    assert!(!cp437_grid.is_null());
 | 
					 | 
				
			||||||
    (*cp437_grid).0.fill(value);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the width of the [SPCp437Grid] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid`: instance to read from
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `cp437_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid` points to a valid [SPCp437Grid]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_cp437_grid_width(
 | 
					 | 
				
			||||||
    cp437_grid: *const SPCp437Grid,
 | 
					 | 
				
			||||||
) -> usize {
 | 
					 | 
				
			||||||
    assert!(!cp437_grid.is_null());
 | 
					 | 
				
			||||||
    (*cp437_grid).0.width()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets the height of the [SPCp437Grid] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid`: instance to read from
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `cp437_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid` points to a valid [SPCp437Grid]
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_cp437_grid_height(
 | 
					 | 
				
			||||||
    cp437_grid: *const SPCp437Grid,
 | 
					 | 
				
			||||||
) -> usize {
 | 
					 | 
				
			||||||
    assert!(!cp437_grid.is_null());
 | 
					 | 
				
			||||||
    (*cp437_grid).0.height()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Gets an unsafe reference to the data of the [SPCp437Grid] instance.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `cp437_grid` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// ## Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `cp437_grid` points to a valid [SPCp437Grid]
 | 
					 | 
				
			||||||
/// - the returned memory range is never accessed after the passed [SPCp437Grid] has been freed
 | 
					 | 
				
			||||||
/// - the returned memory range is never accessed concurrently, either via the [SPCp437Grid] or directly
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_cp437_grid_unsafe_data_ref(
 | 
					 | 
				
			||||||
    cp437_grid: *mut SPCp437Grid,
 | 
					 | 
				
			||||||
) -> SPByteSlice {
 | 
					 | 
				
			||||||
    let data = (*cp437_grid).0.data_ref_mut();
 | 
					 | 
				
			||||||
    SPByteSlice {
 | 
					 | 
				
			||||||
        start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
 | 
					 | 
				
			||||||
        length: data.len(),
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,48 +0,0 @@
 | 
				
			||||||
//! C API wrapper for the [servicepoint](https://docs.rs/servicepoint/latest/servicepoint/) crate.
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! # Examples
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! Make sure to check out [this GitHub repo](https://github.com/arfst23/ServicePoint) as well!
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! ```C
 | 
					 | 
				
			||||||
//! #include <stdio.h>
 | 
					 | 
				
			||||||
//! #include "servicepoint.h"
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! int main(void) {
 | 
					 | 
				
			||||||
//!     SPConnection *connection = sp_connection_open("172.23.42.29:2342");
 | 
					 | 
				
			||||||
//!     if (connection == NULL)
 | 
					 | 
				
			||||||
//!         return 1;
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//!     SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
 | 
					 | 
				
			||||||
//!     sp_bitmap_fill(pixels, true);
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//!     SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
 | 
					 | 
				
			||||||
//!     while (sp_connection_send_command(connection, sp_command_clone(command)));
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//!     sp_command_free(command);
 | 
					 | 
				
			||||||
//!     sp_connection_free(connection);
 | 
					 | 
				
			||||||
//!     return 0;
 | 
					 | 
				
			||||||
//! }
 | 
					 | 
				
			||||||
//! ```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub use crate::bitmap::*;
 | 
					 | 
				
			||||||
pub use crate::bitvec::*;
 | 
					 | 
				
			||||||
pub use crate::brightness_grid::*;
 | 
					 | 
				
			||||||
pub use crate::byte_slice::*;
 | 
					 | 
				
			||||||
pub use crate::char_grid::*;
 | 
					 | 
				
			||||||
pub use crate::command::*;
 | 
					 | 
				
			||||||
pub use crate::connection::*;
 | 
					 | 
				
			||||||
pub use crate::constants::*;
 | 
					 | 
				
			||||||
pub use crate::cp437_grid::*;
 | 
					 | 
				
			||||||
pub use crate::packet::*;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mod bitmap;
 | 
					 | 
				
			||||||
mod bitvec;
 | 
					 | 
				
			||||||
mod brightness_grid;
 | 
					 | 
				
			||||||
mod byte_slice;
 | 
					 | 
				
			||||||
mod char_grid;
 | 
					 | 
				
			||||||
mod command;
 | 
					 | 
				
			||||||
mod connection;
 | 
					 | 
				
			||||||
mod constants;
 | 
					 | 
				
			||||||
mod cp437_grid;
 | 
					 | 
				
			||||||
mod packet;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,166 +0,0 @@
 | 
				
			||||||
//! C functions for interacting with [SPPacket]s
 | 
					 | 
				
			||||||
//!
 | 
					 | 
				
			||||||
//! prefix `sp_packet_`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use std::ptr::{null_mut, NonNull};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::SPCommand;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The raw packet
 | 
					 | 
				
			||||||
pub struct SPPacket(pub(crate) servicepoint::Packet);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Turns a [SPCommand] into a [SPPacket].
 | 
					 | 
				
			||||||
/// The [SPCommand] gets consumed.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `command` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - [SPCommand] points to a valid instance of [SPCommand]
 | 
					 | 
				
			||||||
/// - [SPCommand] is not used concurrently or after this call
 | 
					 | 
				
			||||||
/// - the returned [SPPacket] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_packet_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_packet_from_command(
 | 
					 | 
				
			||||||
    command: *mut SPCommand,
 | 
					 | 
				
			||||||
) -> NonNull<SPPacket> {
 | 
					 | 
				
			||||||
    assert!(!command.is_null());
 | 
					 | 
				
			||||||
    let command = *Box::from_raw(command);
 | 
					 | 
				
			||||||
    let result = Box::new(SPPacket(command.0.into()));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Tries to load a [SPPacket] from the passed array with the specified length.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: NULL in case of an error, pointer to the allocated packet otherwise
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `data` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `data` points to a valid memory region of at least `length` bytes
 | 
					 | 
				
			||||||
/// - `data` is not written to concurrently
 | 
					 | 
				
			||||||
/// - the returned [SPPacket] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_packet_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_packet_try_load(
 | 
					 | 
				
			||||||
    data: *const u8,
 | 
					 | 
				
			||||||
    length: usize,
 | 
					 | 
				
			||||||
) -> *mut SPPacket {
 | 
					 | 
				
			||||||
    assert!(!data.is_null());
 | 
					 | 
				
			||||||
    let data = std::slice::from_raw_parts(data, length);
 | 
					 | 
				
			||||||
    match servicepoint::Packet::try_from(data) {
 | 
					 | 
				
			||||||
        Err(_) => null_mut(),
 | 
					 | 
				
			||||||
        Ok(packet) => Box::into_raw(Box::new(SPPacket(packet))),
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Creates a raw [SPPacket] from parts.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Arguments
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `command_code` specifies which command this packet contains
 | 
					 | 
				
			||||||
/// - `a`, `b`, `c` and `d` are command-specific header values
 | 
					 | 
				
			||||||
/// - `payload` is the optional data that is part of the command
 | 
					 | 
				
			||||||
/// - `payload_len` is the size of the payload
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// returns: new instance. Will never return null.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `payload` is null, but `payload_len` is not zero
 | 
					 | 
				
			||||||
/// - when `payload_len` is zero, but `payload` is nonnull
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `payload` points to a valid memory region of at least `payload_len` bytes
 | 
					 | 
				
			||||||
/// - `payload` is not written to concurrently
 | 
					 | 
				
			||||||
/// - the returned [SPPacket] instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling [sp_packet_free].
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_packet_from_parts(
 | 
					 | 
				
			||||||
    command_code: u16,
 | 
					 | 
				
			||||||
    a: u16,
 | 
					 | 
				
			||||||
    b: u16,
 | 
					 | 
				
			||||||
    c: u16,
 | 
					 | 
				
			||||||
    d: u16,
 | 
					 | 
				
			||||||
    payload: *const u8,
 | 
					 | 
				
			||||||
    payload_len: usize,
 | 
					 | 
				
			||||||
) -> NonNull<SPPacket> {
 | 
					 | 
				
			||||||
    assert_eq!(payload.is_null(), payload_len == 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let payload = if payload.is_null() {
 | 
					 | 
				
			||||||
        vec![]
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        let payload = std::slice::from_raw_parts(payload, payload_len);
 | 
					 | 
				
			||||||
        Vec::from(payload)
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let packet = servicepoint::Packet {
 | 
					 | 
				
			||||||
        header: servicepoint::Header {
 | 
					 | 
				
			||||||
            command_code,
 | 
					 | 
				
			||||||
            a,
 | 
					 | 
				
			||||||
            b,
 | 
					 | 
				
			||||||
            c,
 | 
					 | 
				
			||||||
            d,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        payload,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    let result = Box::new(SPPacket(packet));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Clones a [SPPacket].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Will never return NULL.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `packet` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `packet` points to a valid [SPPacket]
 | 
					 | 
				
			||||||
/// - `packet` is not written to concurrently
 | 
					 | 
				
			||||||
/// - the returned instance is freed in some way, either by using a consuming function or
 | 
					 | 
				
			||||||
///   by explicitly calling `sp_packet_free`.
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_packet_clone(
 | 
					 | 
				
			||||||
    packet: *const SPPacket,
 | 
					 | 
				
			||||||
) -> NonNull<SPPacket> {
 | 
					 | 
				
			||||||
    assert!(!packet.is_null());
 | 
					 | 
				
			||||||
    let result = Box::new(SPPacket((*packet).0.clone()));
 | 
					 | 
				
			||||||
    NonNull::from(Box::leak(result))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Deallocates a [SPPacket].
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Panics
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - when `packet` is NULL
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The caller has to make sure that:
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// - `packet` points to a valid [SPPacket]
 | 
					 | 
				
			||||||
/// - `packet` is not used concurrently or after this call
 | 
					 | 
				
			||||||
#[no_mangle]
 | 
					 | 
				
			||||||
pub unsafe extern "C" fn sp_packet_free(packet: *mut SPPacket) {
 | 
					 | 
				
			||||||
    assert!(!packet.is_null());
 | 
					 | 
				
			||||||
    _ = Box::from_raw(packet)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,61 +0,0 @@
 | 
				
			||||||
[package]
 | 
					 | 
				
			||||||
name = "servicepoint_binding_uniffi"
 | 
					 | 
				
			||||||
version.workspace = true
 | 
					 | 
				
			||||||
publish = false
 | 
					 | 
				
			||||||
edition = "2021"
 | 
					 | 
				
			||||||
license = "GPL-3.0-or-later"
 | 
					 | 
				
			||||||
description = "C bindings for the servicepoint crate."
 | 
					 | 
				
			||||||
homepage = "https://docs.rs/crate/servicepoint_binding_c"
 | 
					 | 
				
			||||||
repository = "https://git.berlin.ccc.de/servicepoint/servicepoint"
 | 
					 | 
				
			||||||
#readme = "README.md"
 | 
					 | 
				
			||||||
keywords = ["cccb", "cccb-servicepoint", "uniffi"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[lib]
 | 
					 | 
				
			||||||
crate-type = ["cdylib"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[build-dependencies]
 | 
					 | 
				
			||||||
uniffi = { version = "0.25.3", features = ["build"] }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies]
 | 
					 | 
				
			||||||
uniffi = { version = "0.25.3" }
 | 
					 | 
				
			||||||
thiserror.workspace = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.servicepoint]
 | 
					 | 
				
			||||||
version = "0.13.1"
 | 
					 | 
				
			||||||
path = "../servicepoint"
 | 
					 | 
				
			||||||
features = ["all_compressions"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.uniffi-bindgen-cs]
 | 
					 | 
				
			||||||
git = "https://github.com/NordSecurity/uniffi-bindgen-cs"
 | 
					 | 
				
			||||||
# tag="v0.8.3+v0.25.0"
 | 
					 | 
				
			||||||
rev = "f68639fbc720b50ebe561ba75c66c84dc456bdce"
 | 
					 | 
				
			||||||
optional = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.uniffi-bindgen-go]
 | 
					 | 
				
			||||||
git = "https://github.com/NordSecurity/uniffi-bindgen-go.git"
 | 
					 | 
				
			||||||
# tag = "0.2.2+v0.25.0"
 | 
					 | 
				
			||||||
rev = "ba23bab72f1a9bcc39ce81924d3d9265598e017c"
 | 
					 | 
				
			||||||
optional = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[lints]
 | 
					 | 
				
			||||||
#workspace = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[package.metadata.docs.rs]
 | 
					 | 
				
			||||||
all-features = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[bin]]
 | 
					 | 
				
			||||||
name = "uniffi-bindgen"
 | 
					 | 
				
			||||||
required-features = ["uniffi/cli"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[bin]]
 | 
					 | 
				
			||||||
name = "uniffi-bindgen-cs"
 | 
					 | 
				
			||||||
required-features = ["cs"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[bin]]
 | 
					 | 
				
			||||||
name = "uniffi-bindgen-go"
 | 
					 | 
				
			||||||
required-features = ["go"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[features]
 | 
					 | 
				
			||||||
default = []
 | 
					 | 
				
			||||||
cs = ["dep:uniffi-bindgen-cs"]
 | 
					 | 
				
			||||||
go = ["dep:uniffi-bindgen-go"]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,90 +0,0 @@
 | 
				
			||||||
# ServicePoint
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall. It is called  "Service Point
 | 
					 | 
				
			||||||
Display" or "Airport Display".
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This crate contains bindings for multiple programming languages, enabling non-rust-developers to use the library.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Also take a look at the main project [README](https://git.berlin.ccc.de/servicepoint/servicepoint/src/branch/main/README.md) for more
 | 
					 | 
				
			||||||
information.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Note on stability
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This library is still in early development.
 | 
					 | 
				
			||||||
You can absolutely use it, and it works, but expect minor breaking changes with every version bump.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Notes on differences to rust library
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Performance will not be as good as the rust version:
 | 
					 | 
				
			||||||
    - most objects are reference counted.
 | 
					 | 
				
			||||||
    - objects with mutating methods will also have a MRSW lock
 | 
					 | 
				
			||||||
- You will not get rust backtraces in release builds of the native code
 | 
					 | 
				
			||||||
- Panic messages will work (PanicException)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Supported languages
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| Language  | Support level | Notes                                                                                           |
 | 
					 | 
				
			||||||
|-----------|---------------|-------------------------------------------------------------------------------------------------|
 | 
					 | 
				
			||||||
| .NET (C#) | Full          | see dedicated section                                                                           |
 | 
					 | 
				
			||||||
| Ruby      | Working       | LD_LIBRARY_PATH has to be set, see example project                                              |
 | 
					 | 
				
			||||||
| Python    | Tested once   | Required project file not included. The shared library will be loaded from the script location. |
 | 
					 | 
				
			||||||
| Go        | untested      |                                                                                                 |
 | 
					 | 
				
			||||||
| Kotlin    | untested      |                                                                                                 |
 | 
					 | 
				
			||||||
| Swift     | untested      |                                                                                                 |
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Installation
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Including this repository as a submodule and building from source is the recommended way of using the library.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
git submodule add https://git.berlin.ccc.de/servicepoint/servicepoint.git
 | 
					 | 
				
			||||||
git commit -m "add servicepoint submodule"
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Run `generate-bindings.sh` to regenerate all bindings. This will also build `libservicepoint.so` (or equivalent on your
 | 
					 | 
				
			||||||
platform).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
For languages not fully supported, there will be no project file for the library, just the naked source file(s).
 | 
					 | 
				
			||||||
If you successfully use a language, please open an issue or PR to add the missing ones.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## .NET (C#)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This is the best supported language.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
F# is not tested. If there are usability or functionality problems, please open an issue.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Currently, the project file is hard-coded for Linux and will need tweaks for other platforms (e.g. `.dylib` instead of `.so`).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
You do not have to compile or copy the rust crate manually, as building `ServicePoint.csproj` also builds it.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Example
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```csharp
 | 
					 | 
				
			||||||
using System.Threading;
 | 
					 | 
				
			||||||
using ServicePoint;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var connection = new Connection("127.0.0.1:2342");
 | 
					 | 
				
			||||||
connection.Send(Command.Clear());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
connection.Send(Command.Brightness(5));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var pixels = Bitmap.NewMaxSized();
 | 
					 | 
				
			||||||
for (ulong offset = 0; offset < ulong.MaxValue; offset++)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    pixels.Fill(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (ulong y = 0; y < pixels.Height(); y++)
 | 
					 | 
				
			||||||
        pixels.Set((y + offset) % pixels.Width(), y, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    connection.Send(Command.BitmapLinearWin(0, 0, pixels));
 | 
					 | 
				
			||||||
    Thread.Sleep(14);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
A full example including project files is available as part of this crate.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Why is there no NuGet-Package?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
NuGet packages are not a good way to distribute native
 | 
					 | 
				
			||||||
binaries ([relevant issue](https://github.com/dotnet/sdk/issues/33845)).
 | 
					 | 
				
			||||||
Because of that, there is no NuGet package you can use directly.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,24 +0,0 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					 | 
				
			||||||
set -e
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cargo build --release
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SCRIPT_PATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
 | 
					 | 
				
			||||||
TARGET_PATH="$(realpath "$SCRIPT_PATH"/../../target/release)"
 | 
					 | 
				
			||||||
SERVICEPOINT_SO="$TARGET_PATH/libservicepoint_binding_uniffi.so"
 | 
					 | 
				
			||||||
LIBRARIES_PATH="$SCRIPT_PATH/libraries"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
echo "Source: $SERVICEPOINT_SO"
 | 
					 | 
				
			||||||
echo "Output: $LIBRARIES_PATH"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
BINDGEN="cargo run --features=uniffi/cli --bin uniffi-bindgen -- "
 | 
					 | 
				
			||||||
BINDGEN_CS="cargo run --features=cs --bin uniffi-bindgen-cs -- "
 | 
					 | 
				
			||||||
BINDGEN_GO="cargo run --features=go --bin uniffi-bindgen-go -- "
 | 
					 | 
				
			||||||
COMMON_ARGS="--library $SERVICEPOINT_SO"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
${BINDGEN} generate $COMMON_ARGS --language python --out-dir "$LIBRARIES_PATH/python"
 | 
					 | 
				
			||||||
${BINDGEN} generate $COMMON_ARGS --language kotlin --out-dir "$LIBRARIES_PATH/kotlin"
 | 
					 | 
				
			||||||
${BINDGEN} generate $COMMON_ARGS --language swift --out-dir "$LIBRARIES_PATH/swift"
 | 
					 | 
				
			||||||
${BINDGEN} generate $COMMON_ARGS --language ruby --out-dir "$LIBRARIES_PATH/ruby/lib"
 | 
					 | 
				
			||||||
${BINDGEN_CS} $COMMON_ARGS --out-dir "$LIBRARIES_PATH/csharp/ServicePoint"
 | 
					 | 
				
			||||||
${BINDGEN_GO} $COMMON_ARGS --out-dir "$LIBRARIES_PATH/go/"
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,4 +0,0 @@
 | 
				
			||||||
go
 | 
					 | 
				
			||||||
kotlin
 | 
					 | 
				
			||||||
python
 | 
					 | 
				
			||||||
swift
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,2 +0,0 @@
 | 
				
			||||||
bin
 | 
					 | 
				
			||||||
obj
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,2 +0,0 @@
 | 
				
			||||||
bin
 | 
					 | 
				
			||||||
obj
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,19 +0,0 @@
 | 
				
			||||||
using System.Threading;
 | 
					 | 
				
			||||||
using ServicePoint;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var connection = new Connection("127.0.0.1:2342");
 | 
					 | 
				
			||||||
connection.Send(Command.Clear());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
connection.Send(Command.Brightness(5));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var pixels = Bitmap.NewMaxSized();
 | 
					 | 
				
			||||||
for (ulong offset = 0; offset < ulong.MaxValue; offset++)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    pixels.Fill(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (ulong y = 0; y < pixels.Height(); y++)
 | 
					 | 
				
			||||||
        pixels.Set((y + offset) % pixels.Width(), y, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    connection.Send(Command.BitmapLinearWin(0, 0, pixels));
 | 
					 | 
				
			||||||
    Thread.Sleep(14);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,15 +0,0 @@
 | 
				
			||||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <PropertyGroup>
 | 
					 | 
				
			||||||
        <OutputType>Exe</OutputType>
 | 
					 | 
				
			||||||
        <TargetFramework>net8.0</TargetFramework>
 | 
					 | 
				
			||||||
        <RootNamespace>ServicePoint.Example</RootNamespace>
 | 
					 | 
				
			||||||
        <ImplicitUsings>disable</ImplicitUsings>
 | 
					 | 
				
			||||||
        <Nullable>enable</Nullable>
 | 
					 | 
				
			||||||
    </PropertyGroup>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <ItemGroup>
 | 
					 | 
				
			||||||
        <ProjectReference Include="../ServicePoint/ServicePoint.csproj"/>
 | 
					 | 
				
			||||||
    </ItemGroup>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</Project>
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,16 +0,0 @@
 | 
				
			||||||
namespace ServicePoint.Tests;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class BitmapTests
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    [Fact]
 | 
					 | 
				
			||||||
    public void BasicFunctions()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        var bitmap = new Bitmap(8, 2);
 | 
					 | 
				
			||||||
        Assert.False(bitmap.Get(0, 0));
 | 
					 | 
				
			||||||
        Assert.False(bitmap.Get(bitmap.Width() - 1, bitmap.Height() - 1));
 | 
					 | 
				
			||||||
        bitmap.Fill(true);
 | 
					 | 
				
			||||||
        Assert.True(bitmap.Get(1, 1));
 | 
					 | 
				
			||||||
        bitmap.Set(1, 1, false);
 | 
					 | 
				
			||||||
        Assert.False(bitmap.Get(1, 1));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,31 +0,0 @@
 | 
				
			||||||
namespace ServicePoint.Tests;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class CharGridTests
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    [Fact]
 | 
					 | 
				
			||||||
    public void BasicFunctions()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        var grid = new CharGrid(8, 2);
 | 
					 | 
				
			||||||
        Assert.Equal("\0", grid.Get(0, 0));
 | 
					 | 
				
			||||||
        Assert.Equal("\0", grid.Get(grid.Width() - 1, grid.Height() - 1));
 | 
					 | 
				
			||||||
        grid.Fill(" ");
 | 
					 | 
				
			||||||
        Assert.Equal(" ", grid.Get(1, 1));
 | 
					 | 
				
			||||||
        grid.Set(1, 1, "-");
 | 
					 | 
				
			||||||
        Assert.Equal("-", grid.Get(1, 1));
 | 
					 | 
				
			||||||
        Assert.Throws<PanicException>(() => grid.Get(8, 2));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [Fact]
 | 
					 | 
				
			||||||
    public void RowAndCol()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        var grid = new CharGrid(3, 2);
 | 
					 | 
				
			||||||
        Assert.Equal("\0\0\0", grid.GetRow(0));
 | 
					 | 
				
			||||||
        grid.Fill(" ");
 | 
					 | 
				
			||||||
        Assert.Equal("  ", grid.GetCol(1));
 | 
					 | 
				
			||||||
        Assert.Throws<CharGridException.OutOfBounds>(() => grid.GetCol(3));
 | 
					 | 
				
			||||||
        Assert.Throws<CharGridException.InvalidSeriesLength>(() => grid.SetRow(1, "Text"));
 | 
					 | 
				
			||||||
        grid.SetRow(1, "Foo");
 | 
					 | 
				
			||||||
        Assert.Equal("Foo", grid.GetRow(1));
 | 
					 | 
				
			||||||
        Assert.Equal(" o", grid.GetCol(2));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,42 +0,0 @@
 | 
				
			||||||
namespace ServicePoint.Tests;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class CommandTests
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    private Connection _connection = Connection.NewFake();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [Fact]
 | 
					 | 
				
			||||||
    public void ClearSendable()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _connection.Send(Command.Clear());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [Fact]
 | 
					 | 
				
			||||||
    public void BrightnessSendable()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _connection.Send(Command.Brightness(5));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [Fact]
 | 
					 | 
				
			||||||
    public void InvalidBrightnessThrows()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Assert.Throws<ServicePointException.InvalidBrightness>(() => Command.Brightness(42));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [Fact]
 | 
					 | 
				
			||||||
    public void FadeOutSendable()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _connection.Send(Command.FadeOut());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [Fact]
 | 
					 | 
				
			||||||
    public void HardResetSendable()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _connection.Send(Command.HardReset());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [Fact]
 | 
					 | 
				
			||||||
    public void BitmapLinearWinSendable()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _connection.Send(Command.BitmapLinearWin(0, 0, Bitmap.NewMaxSized(), CompressionCode.Uncompressed));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,11 +0,0 @@
 | 
				
			||||||
namespace ServicePoint.Tests;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class ConnectionTests
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    [Fact]
 | 
					 | 
				
			||||||
    public void InvalidHostnameThrows()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Assert.Throws<ServicePointException.IoException>(() => new Connection(""));
 | 
					 | 
				
			||||||
        Assert.Throws<ServicePointException.IoException>(() => new Connection("-%6$§"));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,2 +0,0 @@
 | 
				
			||||||
global using Xunit;
 | 
					 | 
				
			||||||
global using ServicePoint;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,27 +0,0 @@
 | 
				
			||||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <PropertyGroup>
 | 
					 | 
				
			||||||
    <TargetFramework>net8.0</TargetFramework>
 | 
					 | 
				
			||||||
    <ImplicitUsings>disable</ImplicitUsings>
 | 
					 | 
				
			||||||
    <Nullable>enable</Nullable>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <IsPackable>false</IsPackable>
 | 
					 | 
				
			||||||
    <IsTestProject>true</IsTestProject>
 | 
					 | 
				
			||||||
  </PropertyGroup>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <ItemGroup>
 | 
					 | 
				
			||||||
    <ProjectReference Include="../ServicePoint/ServicePoint.csproj"/>
 | 
					 | 
				
			||||||
  </ItemGroup>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <ItemGroup>
 | 
					 | 
				
			||||||
    <PackageReference Include="coverlet.collector" Version="6.0.0" />
 | 
					 | 
				
			||||||
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
 | 
					 | 
				
			||||||
    <PackageReference Include="xunit" Version="2.5.3" />
 | 
					 | 
				
			||||||
    <PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
 | 
					 | 
				
			||||||
  </ItemGroup>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <ItemGroup>
 | 
					 | 
				
			||||||
    <Using Include="Xunit" />
 | 
					 | 
				
			||||||
  </ItemGroup>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</Project>
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,14 +0,0 @@
 | 
				
			||||||
 | 
					 | 
				
			||||||
using ServicePoint;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public static class ServicePointConstants
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    private static readonly Constants _instance = ServicepointBindingUniffiMethods.GetConstants();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static readonly ulong PixelWidth = _instance.pixelWidth;
 | 
					 | 
				
			||||||
    public static readonly ulong PixelHeight = _instance.pixelHeight;
 | 
					 | 
				
			||||||
    public static readonly ulong PixelCount = _instance.pixelCount;
 | 
					 | 
				
			||||||
    public static readonly ulong TileWidth = _instance.tileWidth;
 | 
					 | 
				
			||||||
    public static readonly ulong TileHeight = _instance.tileHeight;
 | 
					 | 
				
			||||||
    public static readonly ulong TileSize = _instance.tileSize;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,53 +0,0 @@
 | 
				
			||||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <PropertyGroup>
 | 
					 | 
				
			||||||
        <TargetFramework>net8.0</TargetFramework>
 | 
					 | 
				
			||||||
        <ImplicitUsings>disable</ImplicitUsings>
 | 
					 | 
				
			||||||
        <Nullable>enable</Nullable>
 | 
					 | 
				
			||||||
        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
 | 
					 | 
				
			||||||
    </PropertyGroup>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <PropertyGroup>
 | 
					 | 
				
			||||||
        <PackageId>ServicePoint</PackageId>
 | 
					 | 
				
			||||||
        <Version>0.13.1</Version>
 | 
					 | 
				
			||||||
        <Authors>Repository Authors</Authors>
 | 
					 | 
				
			||||||
        <Company>None</Company>
 | 
					 | 
				
			||||||
        <Product>ServicePoint</Product>
 | 
					 | 
				
			||||||
        <PackageTags>CCCB</PackageTags>
 | 
					 | 
				
			||||||
        <Description>
 | 
					 | 
				
			||||||
            C# bindings for the rust crate servicepoint. You will need a suitable native shared library to use this.
 | 
					 | 
				
			||||||
            For documentation, see the rust documentation: https://docs.rs/servicepoint/latest/servicepoint/.
 | 
					 | 
				
			||||||
            Note that this library is still in early development. Breaking changes are expected before 1.0 is released.
 | 
					 | 
				
			||||||
        </Description>
 | 
					 | 
				
			||||||
        <PackageReadmeFile>README.md</PackageReadmeFile>
 | 
					 | 
				
			||||||
        <PublishRepositoryUrl>true</PublishRepositoryUrl>
 | 
					 | 
				
			||||||
    </PropertyGroup>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <!-- generate C# bindings -->
 | 
					 | 
				
			||||||
    <Target Name="BuildBindings" Condition="'$(Configuration)'=='Release'" BeforeTargets="PrepareForBuild">
 | 
					 | 
				
			||||||
        <Exec Command="cargo build -p servicepoint_binding_uniffi --release"/>
 | 
					 | 
				
			||||||
    </Target>
 | 
					 | 
				
			||||||
    <Target Name="BuildBindings" Condition="'$(Configuration)'=='Debug'" BeforeTargets="PrepareForBuild">
 | 
					 | 
				
			||||||
        <Exec Command="cargo build -p servicepoint_binding_uniffi"/>
 | 
					 | 
				
			||||||
    </Target>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <!-- include native binary in output -->
 | 
					 | 
				
			||||||
    <ItemGroup Condition="'$(Configuration)'=='Debug'">
 | 
					 | 
				
			||||||
        <Content Include="../../../../../target/debug/libservicepoint_binding_uniffi.so" CopyToOutputDirectory="Always">
 | 
					 | 
				
			||||||
            <Link>libservicepoint_binding_uniffi.so</Link>
 | 
					 | 
				
			||||||
        </Content>
 | 
					 | 
				
			||||||
    </ItemGroup>
 | 
					 | 
				
			||||||
    <ItemGroup Condition="'$(Configuration)'=='Release'">
 | 
					 | 
				
			||||||
        <Content Include="../../../../../target/release/libservicepoint_binding_uniffi.so" CopyToOutputDirectory="Always">
 | 
					 | 
				
			||||||
            <Link>libservicepoint_binding_uniffi.so</Link>
 | 
					 | 
				
			||||||
        </Content>
 | 
					 | 
				
			||||||
    </ItemGroup>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <ItemGroup>
 | 
					 | 
				
			||||||
        <!-- add README.md to package -->
 | 
					 | 
				
			||||||
        <None Include="../README.md" Pack="true" PackagePath="\"/>
 | 
					 | 
				
			||||||
        <!-- include link to source code at revision -->
 | 
					 | 
				
			||||||
        <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
 | 
					 | 
				
			||||||
    </ItemGroup>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</Project>
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,34 +0,0 @@
 | 
				
			||||||
 | 
					 | 
				
			||||||
Microsoft Visual Studio Solution File, Format Version 12.00
 | 
					 | 
				
			||||||
# Visual Studio Version 17
 | 
					 | 
				
			||||||
VisualStudioVersion = 17.0.31903.59
 | 
					 | 
				
			||||||
MinimumVisualStudioVersion = 10.0.40219.1
 | 
					 | 
				
			||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint", "ServicePoint\ServicePoint.csproj", "{53576D3C-E32E-49BF-BF10-2DB504E50CE1}"
 | 
					 | 
				
			||||||
EndProject
 | 
					 | 
				
			||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint.Example", "ServicePoint.Example\ServicePoint.Example.csproj", "{FEF24227-090E-46C2-B8F6-ACB5AA1A4309}"
 | 
					 | 
				
			||||||
EndProject
 | 
					 | 
				
			||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint.Tests", "ServicePoint.Tests\ServicePoint.Tests.csproj", "{9DC15508-A980-4135-9FC6-659FF54B4E5C}"
 | 
					 | 
				
			||||||
EndProject
 | 
					 | 
				
			||||||
Global
 | 
					 | 
				
			||||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
					 | 
				
			||||||
		Debug|Any CPU = Debug|Any CPU
 | 
					 | 
				
			||||||
		Release|Any CPU = Release|Any CPU
 | 
					 | 
				
			||||||
	EndGlobalSection
 | 
					 | 
				
			||||||
	GlobalSection(SolutionProperties) = preSolution
 | 
					 | 
				
			||||||
		HideSolutionNode = FALSE
 | 
					 | 
				
			||||||
	EndGlobalSection
 | 
					 | 
				
			||||||
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 | 
					 | 
				
			||||||
		{53576D3C-E32E-49BF-BF10-2DB504E50CE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
					 | 
				
			||||||
		{53576D3C-E32E-49BF-BF10-2DB504E50CE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
					 | 
				
			||||||
		{53576D3C-E32E-49BF-BF10-2DB504E50CE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
					 | 
				
			||||||
		{53576D3C-E32E-49BF-BF10-2DB504E50CE1}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
					 | 
				
			||||||
		{FEF24227-090E-46C2-B8F6-ACB5AA1A4309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
					 | 
				
			||||||
		{FEF24227-090E-46C2-B8F6-ACB5AA1A4309}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
					 | 
				
			||||||
		{FEF24227-090E-46C2-B8F6-ACB5AA1A4309}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
					 | 
				
			||||||
		{FEF24227-090E-46C2-B8F6-ACB5AA1A4309}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
					 | 
				
			||||||
		{9DC15508-A980-4135-9FC6-659FF54B4E5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
					 | 
				
			||||||
		{9DC15508-A980-4135-9FC6-659FF54B4E5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
					 | 
				
			||||||
		{9DC15508-A980-4135-9FC6-659FF54B4E5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
					 | 
				
			||||||
		{9DC15508-A980-4135-9FC6-659FF54B4E5C}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
					 | 
				
			||||||
	EndGlobalSection
 | 
					 | 
				
			||||||
EndGlobal
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
source 'https://rubygems.org'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
gem 'servicepoint', path: '..'
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,19 +0,0 @@
 | 
				
			||||||
PATH
 | 
					 | 
				
			||||||
  remote: ..
 | 
					 | 
				
			||||||
  specs:
 | 
					 | 
				
			||||||
    servicepoint (0.0.0)
 | 
					 | 
				
			||||||
      ffi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GEM
 | 
					 | 
				
			||||||
  remote: https://rubygems.org/
 | 
					 | 
				
			||||||
  specs:
 | 
					 | 
				
			||||||
    ffi (1.17.0-x86_64-linux-gnu)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PLATFORMS
 | 
					 | 
				
			||||||
  x86_64-linux
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEPENDENCIES
 | 
					 | 
				
			||||||
  servicepoint!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
BUNDLED WITH
 | 
					 | 
				
			||||||
   2.3.27
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,25 +0,0 @@
 | 
				
			||||||
require_relative "../lib/servicepoint_binding_uniffi"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
include ServicepointBindingUniffi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
connection = Connection.new("172.23.42.29:2342")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pixels = Bitmap.new_max_sized
 | 
					 | 
				
			||||||
x_offset = 0
 | 
					 | 
				
			||||||
loop do
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pixels.fill(false)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  (0..((pixels.height) -1)).each do |y|
 | 
					 | 
				
			||||||
    pixels.set((y + x_offset) % pixels.width, y, true);
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  command = Command.bitmap_linear_win(0, 0, pixels, CompressionCode::UNCOMPRESSED)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  connection.send(command)
 | 
					 | 
				
			||||||
  sleep 0.0005
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  x_offset += 1
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
LD_LIBRARY_PATH="../../../../../target/release:$LD_LIBRARY_PATH" ruby example.rb
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,13 +0,0 @@
 | 
				
			||||||
Gem::Specification.new do |s|
 | 
					 | 
				
			||||||
  s.name        = "servicepoint"
 | 
					 | 
				
			||||||
  s.version     = "0.13.1"
 | 
					 | 
				
			||||||
  s.summary     = ""
 | 
					 | 
				
			||||||
  s.description = ""
 | 
					 | 
				
			||||||
  s.authors     = ["kaesaecracker"]
 | 
					 | 
				
			||||||
  s.email       = ""
 | 
					 | 
				
			||||||
  s.files       = ["lib/servicepoint_binding_uniffi.rb"]
 | 
					 | 
				
			||||||
  s.homepage    =
 | 
					 | 
				
			||||||
    "https://rubygems.org/gems/hola"
 | 
					 | 
				
			||||||
  s.license       = "MIT"
 | 
					 | 
				
			||||||
  s.add_dependency 'ffi'
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
fn main() {
 | 
					 | 
				
			||||||
    uniffi_bindgen_cs::main().unwrap();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
fn main() {
 | 
					 | 
				
			||||||
    uniffi_bindgen_go::main().unwrap();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
fn main() {
 | 
					 | 
				
			||||||
    uniffi::uniffi_bindgen_main()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,77 +0,0 @@
 | 
				
			||||||
use servicepoint::{DataRef, Grid};
 | 
					 | 
				
			||||||
use std::sync::{Arc, RwLock};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(uniffi::Object)]
 | 
					 | 
				
			||||||
pub struct Bitmap {
 | 
					 | 
				
			||||||
    pub(crate) actual: RwLock<servicepoint::Bitmap>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Bitmap {
 | 
					 | 
				
			||||||
    fn internal_new(actual: servicepoint::Bitmap) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Arc::new(Self {
 | 
					 | 
				
			||||||
            actual: RwLock::new(actual),
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[uniffi::export]
 | 
					 | 
				
			||||||
impl Bitmap {
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn new(width: u64, height: u64) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::Bitmap::new(
 | 
					 | 
				
			||||||
            width as usize,
 | 
					 | 
				
			||||||
            height as usize,
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn new_max_sized() -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::Bitmap::max_sized())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn load(width: u64, height: u64, data: Vec<u8>) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::Bitmap::load(
 | 
					 | 
				
			||||||
            width as usize,
 | 
					 | 
				
			||||||
            height as usize,
 | 
					 | 
				
			||||||
            &data,
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn clone(other: &Arc<Self>) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(other.actual.read().unwrap().clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set(&self, x: u64, y: u64, value: bool) {
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .write()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .set(x as usize, y as usize, value)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get(&self, x: u64, y: u64) -> bool {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().get(x as usize, y as usize)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn fill(&self, value: bool) {
 | 
					 | 
				
			||||||
        self.actual.write().unwrap().fill(value)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn width(&self) -> u64 {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().width() as u64
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn height(&self) -> u64 {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().height() as u64
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn equals(&self, other: &Bitmap) -> bool {
 | 
					 | 
				
			||||||
        let a = self.actual.read().unwrap();
 | 
					 | 
				
			||||||
        let b = other.actual.read().unwrap();
 | 
					 | 
				
			||||||
        *a == *b
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn copy_raw(&self) -> Vec<u8> {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().data_ref().to_vec()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,61 +0,0 @@
 | 
				
			||||||
use std::sync::{Arc, RwLock};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(uniffi::Object)]
 | 
					 | 
				
			||||||
pub struct BitVec {
 | 
					 | 
				
			||||||
    pub(crate) actual: RwLock<servicepoint::BitVec>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl BitVec {
 | 
					 | 
				
			||||||
    fn internal_new(actual: servicepoint::BitVec) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Arc::new(Self {
 | 
					 | 
				
			||||||
            actual: RwLock::new(actual),
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[uniffi::export]
 | 
					 | 
				
			||||||
impl BitVec {
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn new(size: u64) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::BitVec::repeat(false, size as usize))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn load(data: Vec<u8>) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::BitVec::from_slice(&data))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn clone(other: &Arc<Self>) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(other.actual.read().unwrap().clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set(&self, index: u64, value: bool) {
 | 
					 | 
				
			||||||
        self.actual.write().unwrap().set(index as usize, value)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get(&self, index: u64) -> bool {
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .read()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .get(index as usize)
 | 
					 | 
				
			||||||
            .is_some_and(move |bit| *bit)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn fill(&self, value: bool) {
 | 
					 | 
				
			||||||
        self.actual.write().unwrap().fill(value)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn len(&self) -> u64 {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().len() as u64
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn equals(&self, other: &BitVec) -> bool {
 | 
					 | 
				
			||||||
        let a = self.actual.read().unwrap();
 | 
					 | 
				
			||||||
        let b = other.actual.read().unwrap();
 | 
					 | 
				
			||||||
        *a == *b
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn copy_raw(&self) -> Vec<u8> {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().clone().into_vec()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,86 +0,0 @@
 | 
				
			||||||
use servicepoint::{Brightness, DataRef, Grid};
 | 
					 | 
				
			||||||
use std::sync::{Arc, RwLock};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(uniffi::Object)]
 | 
					 | 
				
			||||||
pub struct BrightnessGrid {
 | 
					 | 
				
			||||||
    pub(crate) actual: RwLock<servicepoint::BrightnessGrid>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl BrightnessGrid {
 | 
					 | 
				
			||||||
    fn internal_new(actual: servicepoint::BrightnessGrid) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Arc::new(Self {
 | 
					 | 
				
			||||||
            actual: RwLock::new(actual),
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[uniffi::export]
 | 
					 | 
				
			||||||
impl BrightnessGrid {
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn new(width: u64, height: u64) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::BrightnessGrid::new(
 | 
					 | 
				
			||||||
            width as usize,
 | 
					 | 
				
			||||||
            height as usize,
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn load(width: u64, height: u64, data: Vec<u8>) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::BrightnessGrid::saturating_load(
 | 
					 | 
				
			||||||
            width as usize,
 | 
					 | 
				
			||||||
            height as usize,
 | 
					 | 
				
			||||||
            &data,
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn clone(other: &Arc<Self>) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(other.actual.read().unwrap().clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set(&self, x: u64, y: u64, value: u8) {
 | 
					 | 
				
			||||||
        self.actual.write().unwrap().set(
 | 
					 | 
				
			||||||
            x as usize,
 | 
					 | 
				
			||||||
            y as usize,
 | 
					 | 
				
			||||||
            Brightness::saturating_from(value),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get(&self, x: u64, y: u64) -> u8 {
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .read()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .get(x as usize, y as usize)
 | 
					 | 
				
			||||||
            .into()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn fill(&self, value: u8) {
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .write()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .fill(Brightness::saturating_from(value))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn width(&self) -> u64 {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().width() as u64
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn height(&self) -> u64 {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().height() as u64
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn equals(&self, other: &BrightnessGrid) -> bool {
 | 
					 | 
				
			||||||
        let a = self.actual.read().unwrap();
 | 
					 | 
				
			||||||
        let b = other.actual.read().unwrap();
 | 
					 | 
				
			||||||
        *a == *b
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn copy_raw(&self) -> Vec<u8> {
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .read()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .data_ref()
 | 
					 | 
				
			||||||
            .iter()
 | 
					 | 
				
			||||||
            .map(u8::from)
 | 
					 | 
				
			||||||
            .collect()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,169 +0,0 @@
 | 
				
			||||||
use crate::cp437_grid::Cp437Grid;
 | 
					 | 
				
			||||||
use servicepoint::{Grid, SetValueSeriesError};
 | 
					 | 
				
			||||||
use std::convert::Into;
 | 
					 | 
				
			||||||
use std::sync::{Arc, RwLock};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(uniffi::Object)]
 | 
					 | 
				
			||||||
pub struct CharGrid {
 | 
					 | 
				
			||||||
    pub(crate) actual: RwLock<servicepoint::CharGrid>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(uniffi::Error, thiserror::Error, Debug)]
 | 
					 | 
				
			||||||
pub enum CharGridError {
 | 
					 | 
				
			||||||
    #[error("Exactly one character was expected, but {value:?} was provided")]
 | 
					 | 
				
			||||||
    StringNotOneChar { value: String },
 | 
					 | 
				
			||||||
    #[error("The provided series was expected to have a length of {expected}, but was {actual}")]
 | 
					 | 
				
			||||||
    InvalidSeriesLength { actual: u64, expected: u64 },
 | 
					 | 
				
			||||||
    #[error("The index {index} was out of bounds for size {size}")]
 | 
					 | 
				
			||||||
    OutOfBounds { index: u64, size: u64 },
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[uniffi::export]
 | 
					 | 
				
			||||||
impl CharGrid {
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn new(width: u64, height: u64) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::CharGrid::new(
 | 
					 | 
				
			||||||
            width as usize,
 | 
					 | 
				
			||||||
            height as usize,
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn load(data: String) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::CharGrid::from(&*data))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn clone(other: &Arc<Self>) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(other.actual.read().unwrap().clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set(
 | 
					 | 
				
			||||||
        &self,
 | 
					 | 
				
			||||||
        x: u64,
 | 
					 | 
				
			||||||
        y: u64,
 | 
					 | 
				
			||||||
        value: String,
 | 
					 | 
				
			||||||
    ) -> Result<(), CharGridError> {
 | 
					 | 
				
			||||||
        let value = Self::str_to_char(value)?;
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .write()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .set(x as usize, y as usize, value);
 | 
					 | 
				
			||||||
        Ok(())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get(&self, x: u64, y: u64) -> String {
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .read()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .get(x as usize, y as usize)
 | 
					 | 
				
			||||||
            .into()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn fill(&self, value: String) -> Result<(), CharGridError> {
 | 
					 | 
				
			||||||
        let value = Self::str_to_char(value)?;
 | 
					 | 
				
			||||||
        self.actual.write().unwrap().fill(value);
 | 
					 | 
				
			||||||
        Ok(())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn width(&self) -> u64 {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().width() as u64
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn height(&self) -> u64 {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().height() as u64
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn equals(&self, other: &CharGrid) -> bool {
 | 
					 | 
				
			||||||
        let a = self.actual.read().unwrap();
 | 
					 | 
				
			||||||
        let b = other.actual.read().unwrap();
 | 
					 | 
				
			||||||
        *a == *b
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn as_string(&self) -> String {
 | 
					 | 
				
			||||||
        let grid = self.actual.read().unwrap();
 | 
					 | 
				
			||||||
        String::from(&*grid)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_row(&self, y: u64, row: String) -> Result<(), CharGridError> {
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .write()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .set_row(y as usize, &row.chars().collect::<Vec<_>>())
 | 
					 | 
				
			||||||
            .map_err(CharGridError::from)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_col(&self, x: u64, col: String) -> Result<(), CharGridError> {
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .write()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .set_row(x as usize, &col.chars().collect::<Vec<_>>())
 | 
					 | 
				
			||||||
            .map_err(CharGridError::from)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get_row(&self, y: u64) -> Result<String, CharGridError> {
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .read()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .get_row(y as usize)
 | 
					 | 
				
			||||||
            .map(String::from_iter)
 | 
					 | 
				
			||||||
            .ok_or(CharGridError::OutOfBounds {
 | 
					 | 
				
			||||||
                index: y,
 | 
					 | 
				
			||||||
                size: self.height(),
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get_col(&self, x: u64) -> Result<String, CharGridError> {
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .read()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .get_col(x as usize)
 | 
					 | 
				
			||||||
            .map(String::from_iter)
 | 
					 | 
				
			||||||
            .ok_or(CharGridError::OutOfBounds {
 | 
					 | 
				
			||||||
                index: x,
 | 
					 | 
				
			||||||
                size: self.width(),
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn to_cp437(&self) -> Arc<Cp437Grid> {
 | 
					 | 
				
			||||||
        Cp437Grid::internal_new(servicepoint::Cp437Grid::from(
 | 
					 | 
				
			||||||
            &*self.actual.read().unwrap(),
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl CharGrid {
 | 
					 | 
				
			||||||
    pub(crate) fn internal_new(actual: servicepoint::CharGrid) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Arc::new(Self {
 | 
					 | 
				
			||||||
            actual: RwLock::new(actual),
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn str_to_char(value: String) -> Result<char, CharGridError> {
 | 
					 | 
				
			||||||
        if value.len() != 1 {
 | 
					 | 
				
			||||||
            return Err(CharGridError::StringNotOneChar { value });
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let value = value.chars().nth(0).unwrap();
 | 
					 | 
				
			||||||
        Ok(value)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl From<SetValueSeriesError> for CharGridError {
 | 
					 | 
				
			||||||
    fn from(e: SetValueSeriesError) -> Self {
 | 
					 | 
				
			||||||
        match e {
 | 
					 | 
				
			||||||
            SetValueSeriesError::OutOfBounds { index, size } => {
 | 
					 | 
				
			||||||
                CharGridError::OutOfBounds {
 | 
					 | 
				
			||||||
                    index: index as u64,
 | 
					 | 
				
			||||||
                    size: size as u64,
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            SetValueSeriesError::InvalidLength { actual, expected } => {
 | 
					 | 
				
			||||||
                CharGridError::InvalidSeriesLength {
 | 
					 | 
				
			||||||
                    actual: actual as u64,
 | 
					 | 
				
			||||||
                    expected: expected as u64,
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,175 +0,0 @@
 | 
				
			||||||
use crate::bitmap::Bitmap;
 | 
					 | 
				
			||||||
use crate::bitvec::BitVec;
 | 
					 | 
				
			||||||
use crate::brightness_grid::BrightnessGrid;
 | 
					 | 
				
			||||||
use crate::char_grid::CharGrid;
 | 
					 | 
				
			||||||
use crate::compression_code::CompressionCode;
 | 
					 | 
				
			||||||
use crate::cp437_grid::Cp437Grid;
 | 
					 | 
				
			||||||
use crate::errors::ServicePointError;
 | 
					 | 
				
			||||||
use servicepoint::Origin;
 | 
					 | 
				
			||||||
use std::sync::Arc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(uniffi::Object)]
 | 
					 | 
				
			||||||
pub struct Command {
 | 
					 | 
				
			||||||
    pub(crate) actual: servicepoint::Command,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Command {
 | 
					 | 
				
			||||||
    fn internal_new(actual: servicepoint::Command) -> Arc<Command> {
 | 
					 | 
				
			||||||
        Arc::new(Command { actual })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[uniffi::export]
 | 
					 | 
				
			||||||
impl Command {
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn clear() -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::Command::Clear)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn brightness(brightness: u8) -> Result<Arc<Self>, ServicePointError> {
 | 
					 | 
				
			||||||
        servicepoint::Brightness::try_from(brightness)
 | 
					 | 
				
			||||||
            .map_err(move |value| ServicePointError::InvalidBrightness {
 | 
					 | 
				
			||||||
                value,
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .map(servicepoint::Command::Brightness)
 | 
					 | 
				
			||||||
            .map(Self::internal_new)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn fade_out() -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::Command::FadeOut)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn hard_reset() -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::Command::HardReset)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn bitmap_linear_win(
 | 
					 | 
				
			||||||
        offset_x: u64,
 | 
					 | 
				
			||||||
        offset_y: u64,
 | 
					 | 
				
			||||||
        bitmap: &Arc<Bitmap>,
 | 
					 | 
				
			||||||
        compression: CompressionCode,
 | 
					 | 
				
			||||||
    ) -> Arc<Self> {
 | 
					 | 
				
			||||||
        let origin = Origin::new(offset_x as usize, offset_y as usize);
 | 
					 | 
				
			||||||
        let bitmap = bitmap.actual.read().unwrap().clone();
 | 
					 | 
				
			||||||
        let actual = servicepoint::Command::BitmapLinearWin(
 | 
					 | 
				
			||||||
            origin,
 | 
					 | 
				
			||||||
            bitmap,
 | 
					 | 
				
			||||||
            servicepoint::CompressionCode::try_from(compression as u16)
 | 
					 | 
				
			||||||
                .unwrap(),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        Self::internal_new(actual)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn char_brightness(
 | 
					 | 
				
			||||||
        offset_x: u64,
 | 
					 | 
				
			||||||
        offset_y: u64,
 | 
					 | 
				
			||||||
        grid: &Arc<BrightnessGrid>,
 | 
					 | 
				
			||||||
    ) -> Arc<Self> {
 | 
					 | 
				
			||||||
        let origin = Origin::new(offset_x as usize, offset_y as usize);
 | 
					 | 
				
			||||||
        let grid = grid.actual.read().unwrap().clone();
 | 
					 | 
				
			||||||
        let actual = servicepoint::Command::CharBrightness(origin, grid);
 | 
					 | 
				
			||||||
        Self::internal_new(actual)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn bitmap_linear(
 | 
					 | 
				
			||||||
        offset: u64,
 | 
					 | 
				
			||||||
        bitmap: &Arc<BitVec>,
 | 
					 | 
				
			||||||
        compression: CompressionCode,
 | 
					 | 
				
			||||||
    ) -> Arc<Self> {
 | 
					 | 
				
			||||||
        let bitmap = bitmap.actual.read().unwrap().clone();
 | 
					 | 
				
			||||||
        let actual = servicepoint::Command::BitmapLinear(
 | 
					 | 
				
			||||||
            offset as usize,
 | 
					 | 
				
			||||||
            bitmap,
 | 
					 | 
				
			||||||
            servicepoint::CompressionCode::try_from(compression as u16)
 | 
					 | 
				
			||||||
                .unwrap(),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        Self::internal_new(actual)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn bitmap_linear_and(
 | 
					 | 
				
			||||||
        offset: u64,
 | 
					 | 
				
			||||||
        bitmap: &Arc<BitVec>,
 | 
					 | 
				
			||||||
        compression: CompressionCode,
 | 
					 | 
				
			||||||
    ) -> Arc<Self> {
 | 
					 | 
				
			||||||
        let bitmap = bitmap.actual.read().unwrap().clone();
 | 
					 | 
				
			||||||
        let actual = servicepoint::Command::BitmapLinearAnd(
 | 
					 | 
				
			||||||
            offset as usize,
 | 
					 | 
				
			||||||
            bitmap,
 | 
					 | 
				
			||||||
            servicepoint::CompressionCode::try_from(compression as u16)
 | 
					 | 
				
			||||||
                .unwrap(),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        Self::internal_new(actual)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn bitmap_linear_or(
 | 
					 | 
				
			||||||
        offset: u64,
 | 
					 | 
				
			||||||
        bitmap: &Arc<BitVec>,
 | 
					 | 
				
			||||||
        compression: CompressionCode,
 | 
					 | 
				
			||||||
    ) -> Arc<Self> {
 | 
					 | 
				
			||||||
        let bitmap = bitmap.actual.read().unwrap().clone();
 | 
					 | 
				
			||||||
        let actual = servicepoint::Command::BitmapLinearOr(
 | 
					 | 
				
			||||||
            offset as usize,
 | 
					 | 
				
			||||||
            bitmap,
 | 
					 | 
				
			||||||
            servicepoint::CompressionCode::try_from(compression as u16)
 | 
					 | 
				
			||||||
                .unwrap(),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        Self::internal_new(actual)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn bitmap_linear_xor(
 | 
					 | 
				
			||||||
        offset: u64,
 | 
					 | 
				
			||||||
        bitmap: &Arc<BitVec>,
 | 
					 | 
				
			||||||
        compression: CompressionCode,
 | 
					 | 
				
			||||||
    ) -> Arc<Self> {
 | 
					 | 
				
			||||||
        let bitmap = bitmap.actual.read().unwrap().clone();
 | 
					 | 
				
			||||||
        let actual = servicepoint::Command::BitmapLinearXor(
 | 
					 | 
				
			||||||
            offset as usize,
 | 
					 | 
				
			||||||
            bitmap,
 | 
					 | 
				
			||||||
            servicepoint::CompressionCode::try_from(compression as u16)
 | 
					 | 
				
			||||||
                .unwrap(),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        Self::internal_new(actual)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn cp437_data(
 | 
					 | 
				
			||||||
        offset_x: u64,
 | 
					 | 
				
			||||||
        offset_y: u64,
 | 
					 | 
				
			||||||
        grid: &Arc<Cp437Grid>,
 | 
					 | 
				
			||||||
    ) -> Arc<Self> {
 | 
					 | 
				
			||||||
        let origin = Origin::new(offset_x as usize, offset_y as usize);
 | 
					 | 
				
			||||||
        let grid = grid.actual.read().unwrap().clone();
 | 
					 | 
				
			||||||
        let actual = servicepoint::Command::Cp437Data(origin, grid);
 | 
					 | 
				
			||||||
        Self::internal_new(actual)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn utf8_data(
 | 
					 | 
				
			||||||
        offset_x: u64,
 | 
					 | 
				
			||||||
        offset_y: u64,
 | 
					 | 
				
			||||||
        grid: &Arc<CharGrid>,
 | 
					 | 
				
			||||||
    ) -> Arc<Self> {
 | 
					 | 
				
			||||||
        let origin = Origin::new(offset_x as usize, offset_y as usize);
 | 
					 | 
				
			||||||
        let grid = grid.actual.read().unwrap().clone();
 | 
					 | 
				
			||||||
        let actual = servicepoint::Command::Utf8Data(origin, grid);
 | 
					 | 
				
			||||||
        Self::internal_new(actual)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn clone(other: &Arc<Self>) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(other.actual.clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn equals(&self, other: &Command) -> bool {
 | 
					 | 
				
			||||||
        self.actual == other.actual
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,14 +0,0 @@
 | 
				
			||||||
#[repr(u16)]
 | 
					 | 
				
			||||||
#[derive(Debug, Clone, Copy, PartialEq, uniffi::Enum)]
 | 
					 | 
				
			||||||
pub enum CompressionCode {
 | 
					 | 
				
			||||||
    /// no compression
 | 
					 | 
				
			||||||
    Uncompressed = 0x0,
 | 
					 | 
				
			||||||
    /// compress using flate2 with zlib header
 | 
					 | 
				
			||||||
    Zlib = 0x677a,
 | 
					 | 
				
			||||||
    /// compress using bzip2
 | 
					 | 
				
			||||||
    Bzip2 = 0x627a,
 | 
					 | 
				
			||||||
    /// compress using lzma
 | 
					 | 
				
			||||||
    Lzma = 0x6c7a,
 | 
					 | 
				
			||||||
    /// compress using Zstandard
 | 
					 | 
				
			||||||
    Zstd = 0x7a73,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,36 +0,0 @@
 | 
				
			||||||
use std::sync::Arc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::command::Command;
 | 
					 | 
				
			||||||
use crate::errors::ServicePointError;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(uniffi::Object)]
 | 
					 | 
				
			||||||
pub struct Connection {
 | 
					 | 
				
			||||||
    actual: servicepoint::Connection,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[uniffi::export]
 | 
					 | 
				
			||||||
impl Connection {
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn new(host: String) -> Result<Arc<Self>, ServicePointError> {
 | 
					 | 
				
			||||||
        servicepoint::Connection::open(host)
 | 
					 | 
				
			||||||
            .map(|actual| Arc::new(Connection { actual }))
 | 
					 | 
				
			||||||
            .map_err(|err| ServicePointError::IoError {
 | 
					 | 
				
			||||||
                error: err.to_string(),
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn new_fake() -> Arc<Self> {
 | 
					 | 
				
			||||||
        Arc::new(Self {
 | 
					 | 
				
			||||||
            actual: servicepoint::Connection::Fake,
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn send(&self, command: Arc<Command>) -> Result<(), ServicePointError> {
 | 
					 | 
				
			||||||
        self.actual.send(command.actual.clone()).map_err(|err| {
 | 
					 | 
				
			||||||
            ServicePointError::IoError {
 | 
					 | 
				
			||||||
                error: format!("{err:?}"),
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,23 +0,0 @@
 | 
				
			||||||
#[derive(
 | 
					 | 
				
			||||||
    Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, uniffi::Record,
 | 
					 | 
				
			||||||
)]
 | 
					 | 
				
			||||||
pub struct Constants {
 | 
					 | 
				
			||||||
    pub tile_size: u64,
 | 
					 | 
				
			||||||
    pub tile_width: u64,
 | 
					 | 
				
			||||||
    pub tile_height: u64,
 | 
					 | 
				
			||||||
    pub pixel_width: u64,
 | 
					 | 
				
			||||||
    pub pixel_height: u64,
 | 
					 | 
				
			||||||
    pub pixel_count: u64,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[uniffi::export]
 | 
					 | 
				
			||||||
fn get_constants() -> Constants {
 | 
					 | 
				
			||||||
    Constants {
 | 
					 | 
				
			||||||
        tile_size: servicepoint::TILE_SIZE as u64,
 | 
					 | 
				
			||||||
        tile_width: servicepoint::TILE_WIDTH as u64,
 | 
					 | 
				
			||||||
        tile_height: servicepoint::TILE_HEIGHT as u64,
 | 
					 | 
				
			||||||
        pixel_width: servicepoint::PIXEL_WIDTH as u64,
 | 
					 | 
				
			||||||
        pixel_height: servicepoint::PIXEL_HEIGHT as u64,
 | 
					 | 
				
			||||||
        pixel_count: servicepoint::PIXEL_COUNT as u64,
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,79 +0,0 @@
 | 
				
			||||||
use crate::char_grid::CharGrid;
 | 
					 | 
				
			||||||
use servicepoint::{DataRef, Grid};
 | 
					 | 
				
			||||||
use std::sync::{Arc, RwLock};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(uniffi::Object)]
 | 
					 | 
				
			||||||
pub struct Cp437Grid {
 | 
					 | 
				
			||||||
    pub(crate) actual: RwLock<servicepoint::Cp437Grid>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Cp437Grid {
 | 
					 | 
				
			||||||
    pub(crate) fn internal_new(actual: servicepoint::Cp437Grid) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Arc::new(Self {
 | 
					 | 
				
			||||||
            actual: RwLock::new(actual),
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[uniffi::export]
 | 
					 | 
				
			||||||
impl Cp437Grid {
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn new(width: u64, height: u64) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::Cp437Grid::new(
 | 
					 | 
				
			||||||
            width as usize,
 | 
					 | 
				
			||||||
            height as usize,
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn load(width: u64, height: u64, data: Vec<u8>) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(servicepoint::Cp437Grid::load(
 | 
					 | 
				
			||||||
            width as usize,
 | 
					 | 
				
			||||||
            height as usize,
 | 
					 | 
				
			||||||
            &data,
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[uniffi::constructor]
 | 
					 | 
				
			||||||
    pub fn clone(other: &Arc<Self>) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Self::internal_new(other.actual.read().unwrap().clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set(&self, x: u64, y: u64, value: u8) {
 | 
					 | 
				
			||||||
        self.actual
 | 
					 | 
				
			||||||
            .write()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .set(x as usize, y as usize, value)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get(&self, x: u64, y: u64) -> u8 {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().get(x as usize, y as usize)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn fill(&self, value: u8) {
 | 
					 | 
				
			||||||
        self.actual.write().unwrap().fill(value)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn width(&self) -> u64 {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().width() as u64
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn height(&self) -> u64 {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().height() as u64
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn equals(&self, other: &Cp437Grid) -> bool {
 | 
					 | 
				
			||||||
        let a = self.actual.read().unwrap();
 | 
					 | 
				
			||||||
        let b = other.actual.read().unwrap();
 | 
					 | 
				
			||||||
        *a == *b
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn copy_raw(&self) -> Vec<u8> {
 | 
					 | 
				
			||||||
        self.actual.read().unwrap().data_ref().to_vec()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn to_utf8(&self) -> Arc<CharGrid> {
 | 
					 | 
				
			||||||
        CharGrid::internal_new(servicepoint::CharGrid::from(
 | 
					 | 
				
			||||||
            &*self.actual.read().unwrap(),
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,7 +0,0 @@
 | 
				
			||||||
#[derive(uniffi::Error, thiserror::Error, Debug)]
 | 
					 | 
				
			||||||
pub enum ServicePointError {
 | 
					 | 
				
			||||||
    #[error("An IO error occurred: {error}")]
 | 
					 | 
				
			||||||
    IoError { error: String },
 | 
					 | 
				
			||||||
    #[error("The specified brightness value {value} is out of range")]
 | 
					 | 
				
			||||||
    InvalidBrightness { value: u8 },
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,12 +0,0 @@
 | 
				
			||||||
uniffi::setup_scaffolding!();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mod bitmap;
 | 
					 | 
				
			||||||
mod bitvec;
 | 
					 | 
				
			||||||
mod brightness_grid;
 | 
					 | 
				
			||||||
mod char_grid;
 | 
					 | 
				
			||||||
mod command;
 | 
					 | 
				
			||||||
mod compression_code;
 | 
					 | 
				
			||||||
mod connection;
 | 
					 | 
				
			||||||
mod constants;
 | 
					 | 
				
			||||||
mod cp437_grid;
 | 
					 | 
				
			||||||
mod errors;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
[bindings.csharp]
 | 
					 | 
				
			||||||
namespace = "ServicePoint"
 | 
					 | 
				
			||||||
access_modifier = "public"
 | 
					 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,7 @@ fn main() {
 | 
				
			||||||
    let command = Command::BitmapLinearWin(
 | 
					    let command = Command::BitmapLinearWin(
 | 
				
			||||||
        Origin::ZERO,
 | 
					        Origin::ZERO,
 | 
				
			||||||
        pixels,
 | 
					        pixels,
 | 
				
			||||||
        CompressionCode::Uncompressed,
 | 
					        CompressionCode::default(),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    connection.send(command).expect("send failed");
 | 
					    connection.send(command).expect("send failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,7 @@ fn main() {
 | 
				
			||||||
        let command = Command::BitmapLinearWin(
 | 
					        let command = Command::BitmapLinearWin(
 | 
				
			||||||
            Origin::ZERO,
 | 
					            Origin::ZERO,
 | 
				
			||||||
            field.clone(),
 | 
					            field.clone(),
 | 
				
			||||||
            CompressionCode::Lzma,
 | 
					            CompressionCode::default(),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        connection.send(command).expect("could not send");
 | 
					        connection.send(command).expect("could not send");
 | 
				
			||||||
        thread::sleep(FRAME_PACING);
 | 
					        thread::sleep(FRAME_PACING);
 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,7 @@ fn main() {
 | 
				
			||||||
        let command = Command::BitmapLinearWin(
 | 
					        let command = Command::BitmapLinearWin(
 | 
				
			||||||
            Origin::ZERO,
 | 
					            Origin::ZERO,
 | 
				
			||||||
            pixels.clone(),
 | 
					            pixels.clone(),
 | 
				
			||||||
            CompressionCode::Lzma,
 | 
					            CompressionCode::default(),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        connection.send(command).expect("send failed");
 | 
					        connection.send(command).expect("send failed");
 | 
				
			||||||
        thread::sleep(FRAME_PACING);
 | 
					        thread::sleep(FRAME_PACING);
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ fn main() {
 | 
				
			||||||
        let command = Command::BitmapLinearWin(
 | 
					        let command = Command::BitmapLinearWin(
 | 
				
			||||||
            Origin::ZERO,
 | 
					            Origin::ZERO,
 | 
				
			||||||
            filled_grid,
 | 
					            filled_grid,
 | 
				
			||||||
            CompressionCode::Lzma,
 | 
					            CompressionCode::default(),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        connection.send(command).expect("send failed");
 | 
					        connection.send(command).expect("send failed");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ fn main() {
 | 
				
			||||||
        .send(Command::BitmapLinearWin(
 | 
					        .send(Command::BitmapLinearWin(
 | 
				
			||||||
            Origin::ZERO,
 | 
					            Origin::ZERO,
 | 
				
			||||||
            pixels,
 | 
					            pixels,
 | 
				
			||||||
            CompressionCode::Lzma,
 | 
					            CompressionCode::default(),
 | 
				
			||||||
        ))
 | 
					        ))
 | 
				
			||||||
        .unwrap();
 | 
					        .unwrap();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,7 @@ fn main() {
 | 
				
			||||||
            .send(Command::BitmapLinearWin(
 | 
					            .send(Command::BitmapLinearWin(
 | 
				
			||||||
                Origin::ZERO,
 | 
					                Origin::ZERO,
 | 
				
			||||||
                enabled_pixels.clone(),
 | 
					                enabled_pixels.clone(),
 | 
				
			||||||
                CompressionCode::Lzma,
 | 
					                CompressionCode::default(),
 | 
				
			||||||
            ))
 | 
					            ))
 | 
				
			||||||
            .expect("could not send command to display");
 | 
					            .expect("could not send command to display");
 | 
				
			||||||
        thread::sleep(sleep_duration);
 | 
					        thread::sleep(sleep_duration);
 | 
				
			||||||
| 
						 | 
					@ -139,10 +139,6 @@
 | 
				
			||||||
                  cargo-tarpaulin
 | 
					                  cargo-tarpaulin
 | 
				
			||||||
                ];
 | 
					                ];
 | 
				
			||||||
              })
 | 
					              })
 | 
				
			||||||
              ruby
 | 
					 | 
				
			||||||
              dotnet-sdk_8
 | 
					 | 
				
			||||||
              gcc
 | 
					 | 
				
			||||||
              gnumake
 | 
					 | 
				
			||||||
            ];
 | 
					            ];
 | 
				
			||||||
            LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath (builtins.concatMap (d: d.buildInputs) inputsFrom)}";
 | 
					            LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath (builtins.concatMap (d: d.buildInputs) inputsFrom)}";
 | 
				
			||||||
            RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
 | 
					            RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,8 +72,16 @@ impl Bitmap {
 | 
				
			||||||
    /// - when the width is not dividable by 8
 | 
					    /// - when the width is not dividable by 8
 | 
				
			||||||
    #[must_use]
 | 
					    #[must_use]
 | 
				
			||||||
    pub fn load(width: usize, height: usize, data: &[u8]) -> Self {
 | 
					    pub fn load(width: usize, height: usize, data: &[u8]) -> Self {
 | 
				
			||||||
        assert_eq!(width % 8, 0, "width must be a multiple of 8, but is {width}");
 | 
					        assert_eq!(
 | 
				
			||||||
        assert_eq!(data.len(), height * width / 8, "data length must match dimensions, with 8 pixels per byte.");
 | 
					            width % 8,
 | 
				
			||||||
 | 
					            0,
 | 
				
			||||||
 | 
					            "width must be a multiple of 8, but is {width}"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            data.len(),
 | 
				
			||||||
 | 
					            height * width / 8,
 | 
				
			||||||
 | 
					            "data length must match dimensions, with 8 pixels per byte."
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            width,
 | 
					            width,
 | 
				
			||||||
            height,
 | 
					            height,
 | 
				
			||||||
| 
						 | 
					@ -91,11 +99,23 @@ impl Bitmap {
 | 
				
			||||||
    /// - when the width is not dividable by 8
 | 
					    /// - when the width is not dividable by 8
 | 
				
			||||||
    #[must_use]
 | 
					    #[must_use]
 | 
				
			||||||
    pub fn from_bitvec(width: usize, bit_vec: BitVec) -> Self {
 | 
					    pub fn from_bitvec(width: usize, bit_vec: BitVec) -> Self {
 | 
				
			||||||
        assert_eq!(width % 8, 0, "width must be a multiple of 8, but is {width}");
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            width % 8,
 | 
				
			||||||
 | 
					            0,
 | 
				
			||||||
 | 
					            "width must be a multiple of 8, but is {width}"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        let len = bit_vec.len();
 | 
					        let len = bit_vec.len();
 | 
				
			||||||
        let height = len / width;
 | 
					        let height = len / width;
 | 
				
			||||||
        assert_eq!(0, len % width, "dimension mismatch - len {len} is not dividable by {width}");
 | 
					        assert_eq!(
 | 
				
			||||||
        Self { width, height, bit_vec }
 | 
					            0,
 | 
				
			||||||
 | 
					            len % width,
 | 
				
			||||||
 | 
					            "dimension mismatch - len {len} is not dividable by {width}"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            width,
 | 
				
			||||||
 | 
					            height,
 | 
				
			||||||
 | 
					            bit_vec,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Iterate over all cells in [Bitmap].
 | 
					    /// Iterate over all cells in [Bitmap].
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@ use rand::{
 | 
				
			||||||
/// let val: u8 = b.into();
 | 
					/// let val: u8 = b.into();
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// let b = Brightness::try_from(7).unwrap();
 | 
					/// let b = Brightness::try_from(7).unwrap();
 | 
				
			||||||
/// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
					/// # let connection = Connection::Fake;
 | 
				
			||||||
/// let result = connection.send(Command::Brightness(b));
 | 
					/// let result = connection.send(Command::Brightness(b));
 | 
				
			||||||
/// ```
 | 
					/// ```
 | 
				
			||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
 | 
					#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@ use crate::ByteGrid;
 | 
				
			||||||
/// grid.set(0, 0, Brightness::MIN);
 | 
					/// grid.set(0, 0, Brightness::MIN);
 | 
				
			||||||
/// grid.set(1, 1, Brightness::MIN);
 | 
					/// grid.set(1, 1, Brightness::MIN);
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
					/// # let connection = Connection::Fake;
 | 
				
			||||||
/// connection.send(Command::CharBrightness(Origin::new(3, 7), grid)).unwrap()
 | 
					/// connection.send(Command::CharBrightness(Origin::new(3, 7), grid)).unwrap()
 | 
				
			||||||
/// ```
 | 
					/// ```
 | 
				
			||||||
pub type BrightnessGrid = ValueGrid<Brightness>;
 | 
					pub type BrightnessGrid = ValueGrid<Brightness>;
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,7 @@ pub type Offset = usize;
 | 
				
			||||||
/// # Compression
 | 
					/// # Compression
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Some commands can contain compressed payloads.
 | 
					/// Some commands can contain compressed payloads.
 | 
				
			||||||
/// To get started, use [CompressionCode::Uncompressed].
 | 
					/// To get started, use [CompressionCode::default].
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// If you want to archive the best performance (e.g. latency),
 | 
					/// If you want to archive the best performance (e.g. latency),
 | 
				
			||||||
/// you can try the different compression algorithms for your hardware and use case.
 | 
					/// you can try the different compression algorithms for your hardware and use case.
 | 
				
			||||||
| 
						 | 
					@ -52,7 +52,7 @@ pub type Offset = usize;
 | 
				
			||||||
/// assert_eq!(command, round_tripped);
 | 
					/// assert_eq!(command, round_tripped);
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// // send command
 | 
					/// // send command
 | 
				
			||||||
/// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
					/// # let connection = Connection::Fake;
 | 
				
			||||||
/// connection.send(command).unwrap();
 | 
					/// connection.send(command).unwrap();
 | 
				
			||||||
/// ```
 | 
					/// ```
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
| 
						 | 
					@ -63,7 +63,7 @@ pub enum Command {
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// ```rust
 | 
					    /// ```rust
 | 
				
			||||||
    /// # use servicepoint::{Command, Connection};
 | 
					    /// # use servicepoint::{Command, Connection};
 | 
				
			||||||
    /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
					    /// # let connection = Connection::Fake;
 | 
				
			||||||
    /// connection.send(Command::Clear).unwrap();
 | 
					    /// connection.send(Command::Clear).unwrap();
 | 
				
			||||||
    /// ```
 | 
					    /// ```
 | 
				
			||||||
    Clear,
 | 
					    Clear,
 | 
				
			||||||
| 
						 | 
					@ -125,7 +125,7 @@ pub enum Command {
 | 
				
			||||||
    /// let command = Command::BitmapLinearWin(
 | 
					    /// let command = Command::BitmapLinearWin(
 | 
				
			||||||
    ///    servicepoint::Origin::ZERO,
 | 
					    ///    servicepoint::Origin::ZERO,
 | 
				
			||||||
    ///    pixels,
 | 
					    ///    pixels,
 | 
				
			||||||
    ///    CompressionCode::Uncompressed
 | 
					    ///    CompressionCode::default()
 | 
				
			||||||
    /// );
 | 
					    /// );
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// connection.send(command).expect("send failed");
 | 
					    /// connection.send(command).expect("send failed");
 | 
				
			||||||
| 
						 | 
					@ -138,7 +138,7 @@ pub enum Command {
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// ```rust
 | 
					    /// ```rust
 | 
				
			||||||
    /// # use servicepoint::{Brightness, Command, Connection};
 | 
					    /// # use servicepoint::{Brightness, Command, Connection};
 | 
				
			||||||
    /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
					    /// # let connection = Connection::Fake;
 | 
				
			||||||
    /// let command = Command::Brightness(Brightness::MAX);
 | 
					    /// let command = Command::Brightness(Brightness::MAX);
 | 
				
			||||||
    /// connection.send(command).unwrap();
 | 
					    /// connection.send(command).unwrap();
 | 
				
			||||||
    /// ```
 | 
					    /// ```
 | 
				
			||||||
| 
						 | 
					@ -187,7 +187,7 @@ pub enum Command {
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// ```rust
 | 
					    /// ```rust
 | 
				
			||||||
    /// # use servicepoint::{Command, Connection};
 | 
					    /// # use servicepoint::{Command, Connection};
 | 
				
			||||||
    /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
					    /// # let connection = Connection::Fake;
 | 
				
			||||||
    /// connection.send(Command::HardReset).unwrap();
 | 
					    /// connection.send(Command::HardReset).unwrap();
 | 
				
			||||||
    /// ```
 | 
					    /// ```
 | 
				
			||||||
    HardReset,
 | 
					    HardReset,
 | 
				
			||||||
| 
						 | 
					@ -200,7 +200,7 @@ pub enum Command {
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// ```rust
 | 
					    /// ```rust
 | 
				
			||||||
    /// # use servicepoint::{Command, Connection};
 | 
					    /// # use servicepoint::{Command, Connection};
 | 
				
			||||||
    /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
					    /// # let connection = Connection::Fake;
 | 
				
			||||||
    /// connection.send(Command::FadeOut).unwrap();
 | 
					    /// connection.send(Command::FadeOut).unwrap();
 | 
				
			||||||
    /// ```
 | 
					    /// ```
 | 
				
			||||||
    FadeOut,
 | 
					    FadeOut,
 | 
				
			||||||
| 
						 | 
					@ -213,7 +213,7 @@ pub enum Command {
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// ```rust
 | 
					    /// ```rust
 | 
				
			||||||
    /// # use servicepoint::{Command, Connection};
 | 
					    /// # use servicepoint::{Command, Connection};
 | 
				
			||||||
    /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | 
					    /// # let connection = Connection::Fake;
 | 
				
			||||||
    /// // this sends a packet that does nothing
 | 
					    /// // this sends a packet that does nothing
 | 
				
			||||||
    /// # #[allow(deprecated)]
 | 
					    /// # #[allow(deprecated)]
 | 
				
			||||||
    /// connection.send(Command::BitmapLegacy).unwrap();
 | 
					    /// connection.send(Command::BitmapLegacy).unwrap();
 | 
				
			||||||
| 
						 | 
					@ -119,7 +119,10 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn char_brightness() {
 | 
					    fn char_brightness() {
 | 
				
			||||||
        assert_eq!(CommandCode::try_from(0x0005), Ok(CommandCode::CharBrightness));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            CommandCode::try_from(0x0005),
 | 
				
			||||||
 | 
					            Ok(CommandCode::CharBrightness)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CommandCode::CharBrightness), 0x0005);
 | 
					        assert_eq!(u16::from(CommandCode::CharBrightness), 0x0005);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -144,59 +147,86 @@ mod tests {
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    #[allow(deprecated)]
 | 
					    #[allow(deprecated)]
 | 
				
			||||||
    fn bitmap_legacy() {
 | 
					    fn bitmap_legacy() {
 | 
				
			||||||
        assert_eq!(CommandCode::try_from(0x0010), Ok(CommandCode::BitmapLegacy));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            CommandCode::try_from(0x0010),
 | 
				
			||||||
 | 
					            Ok(CommandCode::BitmapLegacy)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CommandCode::BitmapLegacy), 0x0010);
 | 
					        assert_eq!(u16::from(CommandCode::BitmapLegacy), 0x0010);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn linear() {
 | 
					    fn linear() {
 | 
				
			||||||
        assert_eq!(CommandCode::try_from(0x0012), Ok(CommandCode::BitmapLinear));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            CommandCode::try_from(0x0012),
 | 
				
			||||||
 | 
					            Ok(CommandCode::BitmapLinear)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CommandCode::BitmapLinear), 0x0012);
 | 
					        assert_eq!(u16::from(CommandCode::BitmapLinear), 0x0012);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn linear_and() {
 | 
					    fn linear_and() {
 | 
				
			||||||
        assert_eq!(CommandCode::try_from(0x0014), Ok(CommandCode::BitmapLinearAnd));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            CommandCode::try_from(0x0014),
 | 
				
			||||||
 | 
					            Ok(CommandCode::BitmapLinearAnd)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CommandCode::BitmapLinearAnd), 0x0014);
 | 
					        assert_eq!(u16::from(CommandCode::BitmapLinearAnd), 0x0014);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn linear_xor() {
 | 
					    fn linear_xor() {
 | 
				
			||||||
        assert_eq!(CommandCode::try_from(0x0016), Ok(CommandCode::BitmapLinearXor));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            CommandCode::try_from(0x0016),
 | 
				
			||||||
 | 
					            Ok(CommandCode::BitmapLinearXor)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CommandCode::BitmapLinearXor), 0x0016);
 | 
					        assert_eq!(u16::from(CommandCode::BitmapLinearXor), 0x0016);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    #[cfg(feature = "compression_zlib")]
 | 
					    #[cfg(feature = "compression_zlib")]
 | 
				
			||||||
    fn bitmap_win_zlib() {
 | 
					    fn bitmap_win_zlib() {
 | 
				
			||||||
        assert_eq!(CommandCode::try_from(0x0017), Ok(CommandCode::BitmapLinearWinZlib));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            CommandCode::try_from(0x0017),
 | 
				
			||||||
 | 
					            Ok(CommandCode::BitmapLinearWinZlib)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CommandCode::BitmapLinearWinZlib), 0x0017);
 | 
					        assert_eq!(u16::from(CommandCode::BitmapLinearWinZlib), 0x0017);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    #[cfg(feature = "compression_bzip2")]
 | 
					    #[cfg(feature = "compression_bzip2")]
 | 
				
			||||||
    fn bitmap_win_bzip2() {
 | 
					    fn bitmap_win_bzip2() {
 | 
				
			||||||
        assert_eq!(CommandCode::try_from(0x0018), Ok(CommandCode::BitmapLinearWinBzip2));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            CommandCode::try_from(0x0018),
 | 
				
			||||||
 | 
					            Ok(CommandCode::BitmapLinearWinBzip2)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CommandCode::BitmapLinearWinBzip2), 0x0018);
 | 
					        assert_eq!(u16::from(CommandCode::BitmapLinearWinBzip2), 0x0018);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    #[cfg(feature = "compression_lzma")]
 | 
					    #[cfg(feature = "compression_lzma")]
 | 
				
			||||||
    fn bitmap_win_lzma() {
 | 
					    fn bitmap_win_lzma() {
 | 
				
			||||||
        assert_eq!(CommandCode::try_from(0x0019), Ok(CommandCode::BitmapLinearWinLzma));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            CommandCode::try_from(0x0019),
 | 
				
			||||||
 | 
					            Ok(CommandCode::BitmapLinearWinLzma)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CommandCode::BitmapLinearWinLzma), 0x0019);
 | 
					        assert_eq!(u16::from(CommandCode::BitmapLinearWinLzma), 0x0019);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    #[cfg(feature = "compression_zstd")]
 | 
					    #[cfg(feature = "compression_zstd")]
 | 
				
			||||||
    fn bitmap_win_zstd() {
 | 
					    fn bitmap_win_zstd() {
 | 
				
			||||||
        assert_eq!(CommandCode::try_from(0x001A), Ok(CommandCode::BitmapLinearWinZstd));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            CommandCode::try_from(0x001A),
 | 
				
			||||||
 | 
					            Ok(CommandCode::BitmapLinearWinZstd)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CommandCode::BitmapLinearWinZstd), 0x001A);
 | 
					        assert_eq!(u16::from(CommandCode::BitmapLinearWinZstd), 0x001A);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn bitmap_win_uncompressed() {
 | 
					    fn bitmap_win_uncompressed() {
 | 
				
			||||||
        assert_eq!(CommandCode::try_from(0x0013), Ok(CommandCode::BitmapLinearWinUncompressed));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            CommandCode::try_from(0x0013),
 | 
				
			||||||
 | 
					            Ok(CommandCode::BitmapLinearWinUncompressed)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CommandCode::BitmapLinearWinUncompressed), 0x0013);
 | 
					        assert_eq!(u16::from(CommandCode::BitmapLinearWinUncompressed), 0x0013);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -208,7 +238,10 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn linear_or() {
 | 
					    fn linear_or() {
 | 
				
			||||||
        assert_eq!(CommandCode::try_from(0x0015), Ok(CommandCode::BitmapLinearOr));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            CommandCode::try_from(0x0015),
 | 
				
			||||||
 | 
					            Ok(CommandCode::BitmapLinearOr)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CommandCode::BitmapLinearOr), 0x0015);
 | 
					        assert_eq!(u16::from(CommandCode::BitmapLinearOr), 0x0015);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -66,6 +66,17 @@ impl TryFrom<u16> for CompressionCode {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for CompressionCode {
 | 
				
			||||||
 | 
					    #[cfg(feature = "compression_lzma")]
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        CompressionCode::Lzma
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[cfg(not(feature = "compression_lzma"))]
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        CompressionCode::Uncompressed
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod test {
 | 
					mod test {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
| 
						 | 
					@ -117,4 +128,16 @@ mod test {
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        assert_eq!(u16::from(CompressionCode::Zstd), 0x7a73);
 | 
					        assert_eq!(u16::from(CompressionCode::Zstd), 0x7a73);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    #[cfg(feature = "compression_lzma")]
 | 
				
			||||||
 | 
					    fn default_lzma() {
 | 
				
			||||||
 | 
					        assert_eq!(CompressionCode::default(), CompressionCode::Lzma);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    #[cfg(not(feature = "compression_lzma"))]
 | 
				
			||||||
 | 
					    fn default_uncompressed() {
 | 
				
			||||||
 | 
					        assert_eq!(CompressionCode::default(), CompressionCode::Uncompressed);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -63,7 +63,7 @@ pub const PIXEL_COUNT: usize = PIXEL_WIDTH * PIXEL_HEIGHT;
 | 
				
			||||||
///    connection.send(Command::BitmapLinearWin(
 | 
					///    connection.send(Command::BitmapLinearWin(
 | 
				
			||||||
///            Origin::new(0,0),
 | 
					///            Origin::new(0,0),
 | 
				
			||||||
///            pixels,
 | 
					///            pixels,
 | 
				
			||||||
///            CompressionCode::Lzma
 | 
					///            CompressionCode::default()
 | 
				
			||||||
///        ))
 | 
					///        ))
 | 
				
			||||||
///        .expect("send failed");
 | 
					///        .expect("send failed");
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					use crate::{CharGrid, Cp437Grid};
 | 
				
			||||||
use std::collections::HashMap;
 | 
					use std::collections::HashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Contains functions to convert between UTF-8 and Codepage 437.
 | 
					/// Contains functions to convert between UTF-8 and Codepage 437.
 | 
				
			||||||
| 
						 | 
					@ -71,6 +72,30 @@ impl Cp437Converter {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<&Cp437Grid> for CharGrid {
 | 
				
			||||||
 | 
					    fn from(value: &Cp437Grid) -> Self {
 | 
				
			||||||
 | 
					        value.map(Cp437Converter::cp437_to_char)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<Cp437Grid> for CharGrid {
 | 
				
			||||||
 | 
					    fn from(value: Cp437Grid) -> Self {
 | 
				
			||||||
 | 
					        Self::from(&value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<&CharGrid> for Cp437Grid {
 | 
				
			||||||
 | 
					    fn from(value: &CharGrid) -> Self {
 | 
				
			||||||
 | 
					        value.map(Cp437Converter::char_to_cp437)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<CharGrid> for Cp437Grid {
 | 
				
			||||||
 | 
					    fn from(value: CharGrid) -> Self {
 | 
				
			||||||
 | 
					        Self::from(&value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests_feature_cp437 {
 | 
					mod tests_feature_cp437 {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
| 
						 | 
					@ -112,4 +137,12 @@ mod tests_feature_cp437 {
 | 
				
			||||||
            '?'
 | 
					            '?'
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn round_trip_cp437() {
 | 
				
			||||||
 | 
					        let utf8 = CharGrid::load(2, 2, &['Ä', 'x', '\n', '$']);
 | 
				
			||||||
 | 
					        let cp437 = Cp437Grid::from(utf8.clone());
 | 
				
			||||||
 | 
					        let actual = CharGrid::from(cp437);
 | 
				
			||||||
 | 
					        assert_eq!(actual, utf8);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					use crate::Grid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A grid containing codepage 437 characters.
 | 
					/// A grid containing codepage 437 characters.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// The encoding is currently not enforced.
 | 
					/// The encoding is currently not enforced.
 | 
				
			||||||
| 
						 | 
					@ -76,39 +78,6 @@ impl Cp437Grid {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::Grid;
 | 
					 | 
				
			||||||
#[allow(unused)] // depends on features
 | 
					 | 
				
			||||||
pub use feature_cp437::*;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(feature = "cp437")]
 | 
					 | 
				
			||||||
mod feature_cp437 {
 | 
					 | 
				
			||||||
    use super::*;
 | 
					 | 
				
			||||||
    use crate::{CharGrid, Cp437Converter};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    impl From<&Cp437Grid> for CharGrid {
 | 
					 | 
				
			||||||
        fn from(value: &Cp437Grid) -> Self {
 | 
					 | 
				
			||||||
            value.map(Cp437Converter::cp437_to_char)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    impl From<Cp437Grid> for CharGrid {
 | 
					 | 
				
			||||||
        fn from(value: Cp437Grid) -> Self {
 | 
					 | 
				
			||||||
            Self::from(&value)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    impl From<&CharGrid> for Cp437Grid {
 | 
					 | 
				
			||||||
        fn from(value: &CharGrid) -> Self {
 | 
					 | 
				
			||||||
            value.map(Cp437Converter::char_to_cp437)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    impl From<CharGrid> for Cp437Grid {
 | 
					 | 
				
			||||||
        fn from(value: CharGrid) -> Self {
 | 
					 | 
				
			||||||
            Self::from(&value)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
| 
						 | 
					@ -146,18 +115,3 @@ mod tests {
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(test)]
 | 
					 | 
				
			||||||
#[cfg(feature = "cp437")]
 | 
					 | 
				
			||||||
mod tests_feature_cp437 {
 | 
					 | 
				
			||||||
    use super::*;
 | 
					 | 
				
			||||||
    use crate::CharGrid;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[test]
 | 
					 | 
				
			||||||
    fn round_trip_cp437() {
 | 
					 | 
				
			||||||
        let utf8 = CharGrid::load(2, 2, &['Ä', 'x', '\n', '$']);
 | 
					 | 
				
			||||||
        let cp437 = Cp437Grid::from(utf8.clone());
 | 
					 | 
				
			||||||
        let actual = CharGrid::from(cp437);
 | 
					 | 
				
			||||||
        assert_eq!(actual, utf8);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,7 @@
 | 
				
			||||||
//!  let command = Command::BitmapLinearWin(
 | 
					//!  let command = Command::BitmapLinearWin(
 | 
				
			||||||
//!     servicepoint::Origin::ZERO,
 | 
					//!     servicepoint::Origin::ZERO,
 | 
				
			||||||
//!     pixels,
 | 
					//!     pixels,
 | 
				
			||||||
//!     CompressionCode::Uncompressed
 | 
					//!     CompressionCode::default()
 | 
				
			||||||
//!  );
 | 
					//!  );
 | 
				
			||||||
//!
 | 
					//!
 | 
				
			||||||
//!  // send command to display
 | 
					//!  // send command to display
 | 
				
			||||||
| 
						 | 
					@ -65,7 +65,6 @@ pub use crate::command::{Command, Offset};
 | 
				
			||||||
pub use crate::compression_code::CompressionCode;
 | 
					pub use crate::compression_code::CompressionCode;
 | 
				
			||||||
pub use crate::connection::Connection;
 | 
					pub use crate::connection::Connection;
 | 
				
			||||||
pub use crate::constants::*;
 | 
					pub use crate::constants::*;
 | 
				
			||||||
pub use crate::cp437::Cp437Converter;
 | 
					 | 
				
			||||||
pub use crate::cp437_grid::Cp437Grid;
 | 
					pub use crate::cp437_grid::Cp437Grid;
 | 
				
			||||||
pub use crate::data_ref::DataRef;
 | 
					pub use crate::data_ref::DataRef;
 | 
				
			||||||
pub use crate::grid::Grid;
 | 
					pub use crate::grid::Grid;
 | 
				
			||||||
| 
						 | 
					@ -97,6 +96,9 @@ mod value_grid;
 | 
				
			||||||
#[cfg(feature = "cp437")]
 | 
					#[cfg(feature = "cp437")]
 | 
				
			||||||
mod cp437;
 | 
					mod cp437;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(feature = "cp437")]
 | 
				
			||||||
 | 
					pub use crate::cp437::Cp437Converter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// include README.md in doctest
 | 
					// include README.md in doctest
 | 
				
			||||||
#[doc = include_str!("../README.md")]
 | 
					#[doc = include_str!("../README.md")]
 | 
				
			||||||
#[cfg(doctest)]
 | 
					#[cfg(doctest)]
 | 
				
			||||||
| 
						 | 
					@ -90,8 +90,16 @@ impl<T: Value> ValueGrid<T> {
 | 
				
			||||||
    pub fn from_vec(width: usize, data: Vec<T>) -> Self {
 | 
					    pub fn from_vec(width: usize, data: Vec<T>) -> Self {
 | 
				
			||||||
        let len = data.len();
 | 
					        let len = data.len();
 | 
				
			||||||
        let height = len / width;
 | 
					        let height = len / width;
 | 
				
			||||||
        assert_eq!(0, len % width, "dimension mismatch - len {len} is not dividable by {width}");
 | 
					        assert_eq!(
 | 
				
			||||||
        Self { data, width, height }        
 | 
					            0,
 | 
				
			||||||
 | 
					            len % width,
 | 
				
			||||||
 | 
					            "dimension mismatch - len {len} is not dividable by {width}"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            data,
 | 
				
			||||||
 | 
					            width,
 | 
				
			||||||
 | 
					            height,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Loads a [ValueGrid] with the specified width from the provided data, wrapping to as many rows as needed.
 | 
					    /// Loads a [ValueGrid] with the specified width from the provided data, wrapping to as many rows as needed.
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue