Merge pull request #1 from kaesaecracker/restructure

Restructure, build.rs, move c_api
This commit is contained in:
Vinzenz Schroeter 2024-05-26 15:17:38 +02:00 committed by GitHub
commit 333cf954f8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
73 changed files with 1643 additions and 1762 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@ target
out
bin
obj
.direnv

379
Cargo.lock generated
View file

@ -17,15 +17,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "announce"
version = "0.1.0"
dependencies = [
"clap",
"env_logger",
"servicepoint2",
]
[[package]]
name = "anstream"
version = "0.6.14"
@ -75,6 +66,35 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "bzip2"
version = "0.4.4"
@ -97,10 +117,29 @@ dependencies = [
]
[[package]]
name = "cc"
version = "1.0.97"
name = "cbindgen"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49"
dependencies = [
"clap 3.2.25",
"heck 0.4.1",
"indexmap",
"log",
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn 1.0.109",
"tempfile",
"toml",
]
[[package]]
name = "cc"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
dependencies = [
"jobserver",
"libc",
@ -113,6 +152,21 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "3.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
dependencies = [
"atty",
"bitflags 1.3.2",
"clap_lex 0.2.4",
"indexmap",
"strsim 0.10.0",
"termcolor",
"textwrap",
]
[[package]]
name = "clap"
version = "4.5.4"
@ -131,8 +185,8 @@ checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
"clap_lex 0.7.0",
"strsim 0.11.1",
]
[[package]]
@ -141,10 +195,19 @@ version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
dependencies = [
"heck",
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.63",
"syn 2.0.66",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]]
@ -161,9 +224,9 @@ checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
[[package]]
name = "crc32fast"
version = "1.4.0"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
@ -179,27 +242,20 @@ dependencies = [
]
[[package]]
name = "env_filter"
version = "0.1.0"
name = "errno"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"log",
"regex",
"libc",
"windows-sys",
]
[[package]]
name = "env_logger"
version = "0.11.3"
name = "fastrand"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"humantime",
"log",
]
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]]
name = "flate2"
@ -211,16 +267,6 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "game_of_life"
version = "0.1.0"
dependencies = [
"clap",
"env_logger",
"rand",
"servicepoint2",
]
[[package]]
name = "getrandom"
version = "0.2.15"
@ -232,6 +278,18 @@ dependencies = [
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
@ -239,10 +297,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "humantime"
version = "2.1.0"
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "is_terminal_polyfill"
@ -250,6 +321,12 @@ version = "1.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "jobserver"
version = "0.1.31"
@ -259,11 +336,25 @@ dependencies = [
"libc",
]
[[package]]
name = "lang_c"
version = "0.1.0"
dependencies = [
"cc",
"servicepoint_binding_c",
]
[[package]]
name = "libc"
version = "0.2.154"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "log"
@ -279,28 +370,25 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "miniz_oxide"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
dependencies = [
"adler",
]
[[package]]
name = "moving_line"
version = "0.1.0"
dependencies = [
"clap",
"env_logger",
"servicepoint2",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "os_str_bytes"
version = "6.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
[[package]]
name = "pkg-config"
version = "0.3.30"
@ -315,9 +403,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.82"
version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
dependencies = [
"unicode-ident",
]
@ -361,16 +449,6 @@ dependencies = [
"getrandom",
]
[[package]]
name = "random_brightness"
version = "0.1.0"
dependencies = [
"clap",
"env_logger",
"rand",
"servicepoint2",
]
[[package]]
name = "regex"
version = "1.10.4"
@ -411,24 +489,91 @@ dependencies = [
]
[[package]]
name = "servicepoint-binding-cs"
version = "0.4.2"
name = "rustix"
version = "0.38.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
dependencies = [
"csbindgen",
"servicepoint2",
"bitflags 2.5.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "servicepoint2"
version = "0.4.2"
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "serde"
version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.66",
]
[[package]]
name = "serde_json"
version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "servicepoint"
version = "0.5.0"
dependencies = [
"bzip2",
"clap 4.5.4",
"flate2",
"log",
"rand",
"rust-lzma",
"zstd",
]
[[package]]
name = "servicepoint_binding_c"
version = "0.5.0"
dependencies = [
"cbindgen",
"servicepoint",
]
[[package]]
name = "servicepoint_binding_cs"
version = "0.5.0"
dependencies = [
"csbindgen",
"servicepoint",
"servicepoint_binding_c",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "strsim"
version = "0.11.1"
@ -448,15 +593,51 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.63"
version = "2.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
dependencies = [
"cfg-if",
"fastrand",
"rustix",
"windows-sys",
]
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
@ -481,6 +662,37 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
dependencies = [
"windows-sys",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.52.0"
@ -554,15 +766,6 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]]
name = "wiping_clear"
version = "0.1.0"
dependencies = [
"clap",
"env_logger",
"servicepoint2",
]
[[package]]
name = "zstd"
version = "0.13.1"

View file

@ -1,11 +1,11 @@
[workspace]
resolver = "2"
members = [
"servicepoint2",
"servicepoint2-binding-cs",
"examples/announce",
"examples/game_of_life",
"examples/moving_line",
"examples/wiping_clear",
"examples/random_brightness"
"crates/servicepoint",
"crates/servicepoint_binding_c",
"crates/servicepoint_binding_cs",
"crates/servicepoint_binding_c/examples/lang_c"
]
[workspace.package]
version = "0.5.0"

203
README.md
View file

@ -1,160 +1,73 @@
# servicepoint2
[![crates.io](https://img.shields.io/crates/v/servicepoint2.svg)](https://crates.io/crates/servicepoint2)
[![Crates.io Total Downloads](https://img.shields.io/crates/d/servicepoint2)](https://crates.io/crates/servicepoint2)
[![docs.rs](https://img.shields.io/docsrs/servicepoint2)](https://docs.rs/servicepoint2/latest/servicepoint2/)
[![GPLv3 licensed](https://img.shields.io/crates/l/servicepoint2)](./LICENSE)
# 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 repository contains a library for parsing, encoding and sending packets to this display via UDP.
This repository contains a library for parsing, encoding and sending packets to this display via UDP in multiple
programming languages.
## Note on stability
Take a look at the contained crates for language specific information:
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.
Expect bugs and/or missing features in the language bindings for now. If you need something specific, open an issue or a pull request.
## Rust
This is where the library works the best.
Any API usage accepted by the compiler in a safe context is either safe or buggy (issues welcome)
```bash
cargo add servicepoint2
```
```rust
fn main() {
// establish connection
let connection = servicepoint2::Connection::open("172.23.42.29:2342")
.expect("connection failed");
// clear screen content
connection.send(servicepoint2::Command::Clear.into())
.expect("send failed");
}
```
More examples are available in the repository folder and in the [Projects using the library]() section
## C / C++
The lowest common denominator. Things to keep in mind:
- This is a chainsaw. You will cut your leg.
- function names are: `sp2_` \<struct_name\> \<rust name\>.
- Use the rust documentation.
- Instances get consumed in the same way they do when writing rust / C# 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.
```c++
#include <stdio.h>
#include "servicepoint2.h"
int main(void) {
sp2_Connection *connection = sp2_connection_open("localhost:2342");
if (connection == NULL)
return 1;
sp2_PixelGrid *pixels = sp2_pixel_grid_new(sp2_PIXEL_WIDTH, sp2_PIXEL_HEIGHT);
sp2_pixel_grid_fill(pixels, true);
sp2_Command *command = sp2_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
sp2_Packet *packet = sp2_packet_from_command(command);
if (!sp2_connection_send(connection, packet))
return 1;
sp2_connection_dealloc(connection);
return 0;
}
```
## C# / F#
Uses C bindings internally to provide a similar API to rust. Things to keep in mind:
- You will get a `NullPointerException` when trying to call a method where the native instance has been consumed already (e.g. when `Send`ing a command instance twice). Send a clone instead of the original if you want to keep using it.
- Some lower-level APIs _will_ panic in native code when used improperly.
Example: manipulating the `Span<byte>` of an object after freeing the instance.
- C# specifics are documented in the library. Use the rust documentation for everything else. Naming and semantics are the same apart from CamelCase instead of kebab_case.
- You will only get rust backtraces in debug builds of the native code.
- F# is not explicitly tested. If there are usability or functionality problems, please open an issue.
- Reading and writing to instances concurrently is not safe. Only reading concurrently is safe.
```csharp
using ServicePoint2;
// using statement calls Dispose() on scope exit, which frees unmanaged instances
using var connection = Connection.Open("127.0.0.1:2342");
using var pixels = PixelGrid.New(Constants.PixelWidth, Constants.PixelHeight);
while (true)
{
pixels.Fill(true);
connection.Send(Command.BitmapLinearWin(0, 0, pixels.Clone()));
Thread.Sleep(5000);
pixels.Fill(false);
connection.Send(Command.BitmapLinearWin(0, 0, pixels.Clone()));
Thread.Sleep(5000);
}
```
### Installation
NuGet packages are not a good way to distribute native projects ([relevant issue](https://github.com/dotnet/sdk/issues/33845)).
Because of that, there is no NuGet package you can use directly.
Including this repository as a submodule and building from source is the recommended way of using the library.
```bash
git submodule add https://github.com/kaesaecracker/servicepoint.git
git commit -m "add servicepoint submodule"
```
You can now reference `servicepoint2-bindings-cs/src/ServicePoint2.csproj` in your project.
The rust library will automatically be built.
Please provide more information in the form of an issue if you need the build to copy a different library file for your platform.
### 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.
## Features
This library has multiple compression libraries as optional dependencies.
If you do not need compression/decompression support you can disable those features.
In the likely case you only need one of them, you can include that one specifically.
```toml
[dependencies.servicepoint2]
git = "https://github.com/kaesaecracker/servicepoint.git"
default-features = false
features = ["compression-bz"]
```
Language bindings will not know which features are available and may fail at runtime.
It is recommended to include all features for builds used outside of rust.
| Language | Readme |
|----------|---------------------------------------------------------------------|
| Rust | [servicepoint](crates/servicepoint/README.md) |
| C / C++ | [servicepoint_binding_c](crates/servicepoint_binding_c/README.md) |
| C# / F# | [servicepoint_binding_cs](crates/servicepoint_binding_cs/README.md) |
## Projects using the library
- screen simulator (rust): https://github.com/kaesaecracker/pixel-receiver-rs
- tanks game (C#): https://github.com/kaesaecracker/cccb-tanks-cs
- screen simulator (rust): [servicepoint-simulator](https://github.com/kaesaecracker/servicepoint-simulator)
- tanks game (C#): [servicepoint-tanks](https://github.com/kaesaecracker/cccb-tanks-cs)
- cellular automata slideshow (rust): [servicepoint-life](https://github.com/kaesaecracker/servicepoint-life)
To add yourself to the list, open a pull request.
## Where is servicepoint1?
## About the display
This library is a spiritual mix of a not-yet-working rust library called `servicepoint` and a bunch of working but also unfinished C# code. Because most of the API concept and a bunch of code is taken from the rust library, the result is called `servicepoint2`.
- Resolution: 352x160=56,320 pixels
- Pixels are grouped into 44x20=880 tiles (8x8=64 pixels each)
- Smallest addressable unit: row of pixels inside of a tile (8 pixels = 1 byte)
- The brightness can only be set per tile
- Screen content can be changed using a simple UDP protocol
- Between each row of tiles, there is a gap of around 4 pixels size. This gap changes the aspect ratio of the display.
### Binary format
A UDP package sent to the display has a header size of 10 bytes.
Each header value has a size of two bytes (unsigned 16 bit integer).
Depending on the command, there can be a payload following the header.
The commands are implemented in DisplayCommands.
To change screen contents, these commands are the most relevant:
1. Clear screen
- command: `0x0002`
- (rest does not matter)
2. Send CP437 data: render specified text into rectangular region
- command: `0x0003`
- top left tile x
- top left tile y
- width in tiles
- height in tiles
- payload: (width in tiles * height in tiles) bytes
- 1 byte = 1 character
- each character is rendered into one tile (mono-spaced)
- characters are encoded using code page 437
3. Send bitmap window: set pixel states for a rectangular region
- command: `0x0013`
- top left tile x
- top left _pixel_ y
- width in tiles
- height in _pixels_
- payload: (width in tiles * height in pixels) bytes
- network byte order
- 1 bit = 1 pixel
There are other commands implemented as well, e.g. for changing the brightness.
## What happened to servicepoint2?
After `servicepoint2` has been merged into `servicepoint`, `servicepoint2` will not continue to get any updates.
## Contributing

View file

@ -1,16 +1,16 @@
[package]
name = "servicepoint2"
version = "0.4.2"
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/servicepoint2"
repository = "https://github.com/kaesaecracker/servicepoint"
readme = "../README.md"
homepage = "https://docs.rs/crate/servicepoint"
repository = "https://github.com/cccb/servicepoint"
readme = "README.md"
[lib]
crate-type = ["staticlib", "rlib", "cdylib"]
crate-type = ["rlib"]
[dependencies]
log = "0.4"
@ -26,4 +26,8 @@ compression_bzip2 = ["dep:bzip2"]
compression_lzma = ["dep:rust-lzma"]
compression_zstd = ["dep:zstd"]
all_compressions = ["compression_zlib", "compression_bzip2", "compression_lzma", "compression_zstd"]
c_api = []
[dev-dependencies]
# for examples
clap = { version = "4.5", features = ["derive"] }
rand = "0.8"

View file

@ -0,0 +1,54 @@
# servicepoint
[![crates.io](https://img.shields.io/crates/v/servicepoint.svg)](https://crates.io/crates/servicepoint)
[![Crates.io Total Downloads](https://img.shields.io/crates/d/servicepoint)](https://crates.io/crates/servicepoint)
[![docs.rs](https://img.shields.io/docsrs/servicepoint)](https://docs.rs/servicepoint/latest/servicepoint/)
[![GPLv3 licensed](https://img.shields.io/crates/l/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.
## Examples
```rust
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.into())
.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 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
```bash
cargo add servicepoint
```
## Features
This library has multiple compression libraries as optional dependencies.
If you do not need compression/decompression support you can disable those features.
In the likely case you only need one of them, you can include that one specifically.
```toml
[dependencies]
servicepoint = { version = "0.5.0", default-features = false, features = ["compression-bz"] }
```
## Everything else
Look at the main project [README](https://github.com/cccb/servicepoint/blob/main/README.md) for further information.

View file

@ -1,6 +1,6 @@
use clap::Parser;
use servicepoint2::{ByteGrid, Command, Connection, Grid, Origin};
use servicepoint::{ByteGrid, Command, Connection, Grid, Origin};
#[derive(Parser, Debug)]
struct Cli {
@ -14,10 +14,11 @@ struct Cli {
/// example: `cargo run -- --text "Hallo,
/// CCCB"`
fn main() {
env_logger::init();
let cli = Cli::parse();
let mut cli = Cli::parse();
if cli.text.is_empty() {
cli.text.push("Hello, CCCB!".to_string());
}
let connection = Connection::open(&cli.destination).unwrap();
if cli.clear {

View file

@ -3,7 +3,7 @@ use std::thread;
use clap::Parser;
use rand::{distributions, Rng};
use servicepoint2::*;
use servicepoint::*;
#[derive(Parser, Debug)]
struct Cli {
@ -14,7 +14,6 @@ struct Cli {
}
fn main() {
env_logger::init();
let cli = Cli::parse();
let connection = Connection::open(&cli.destination).unwrap();
@ -22,13 +21,11 @@ fn main() {
loop {
connection
.send(
Command::BitmapLinearWin(
Origin(0, 0),
field.clone(),
CompressionCode::Lzma,
)
)
.send(Command::BitmapLinearWin(
Origin(0, 0),
field.clone(),
CompressionCode::Lzma,
))
.expect("could not send");
thread::sleep(FRAME_PACING);
field = iteration(field);

View file

@ -2,7 +2,7 @@ use std::thread;
use clap::Parser;
use servicepoint2::*;
use servicepoint::*;
#[derive(Parser, Debug)]
struct Cli {
@ -11,8 +11,6 @@ struct Cli {
}
fn main() {
env_logger::init();
let connection = Connection::open(Cli::parse().destination).unwrap();
let mut pixels = PixelGrid::max_sized();
@ -23,13 +21,11 @@ fn main() {
pixels.set((y + x_offset) % PIXEL_WIDTH, y, true);
}
connection
.send(
Command::BitmapLinearWin(
Origin(0, 0),
pixels.clone(),
CompressionCode::Lzma,
)
)
.send(Command::BitmapLinearWin(
Origin(0, 0),
pixels.clone(),
CompressionCode::Lzma,
))
.unwrap();
thread::sleep(FRAME_PACING);
}

View file

@ -3,8 +3,8 @@ use std::time::Duration;
use clap::Parser;
use rand::Rng;
use servicepoint2::Command::{BitmapLinearWin, Brightness, CharBrightness};
use servicepoint2::*;
use servicepoint::Command::{BitmapLinearWin, Brightness, CharBrightness};
use servicepoint::*;
#[derive(Parser, Debug)]
struct Cli {
@ -17,7 +17,6 @@ struct Cli {
}
fn main() {
env_logger::init();
let cli = Cli::parse();
let connection = Connection::open(cli.destination).unwrap();
@ -55,9 +54,7 @@ fn main() {
}
}
connection
.send(CharBrightness(origin, luma))
.unwrap();
connection.send(CharBrightness(origin, luma)).unwrap();
std::thread::sleep(wait_duration);
}
}

View file

@ -3,7 +3,7 @@ use std::time::Duration;
use clap::Parser;
use servicepoint2::*;
use servicepoint::*;
#[derive(Parser, Debug)]
struct Cli {
@ -14,7 +14,6 @@ struct Cli {
}
fn main() {
env_logger::init();
let cli = Cli::parse();
let sleep_duration = Duration::max(
@ -37,9 +36,7 @@ fn main() {
let bit_vec = BitVec::from(&*pixel_data);
connection
.send(
Command::BitmapLinearAnd(0, bit_vec, CompressionCode::Lzma)
)
.send(Command::BitmapLinearAnd(0, bit_vec, CompressionCode::Lzma))
.unwrap();
thread::sleep(sleep_duration);
}

View file

@ -72,7 +72,7 @@ impl BitVec {
///
/// # Examples
/// ```
/// use servicepoint2::BitVec;
/// use servicepoint::BitVec;
/// let mut vec = BitVec::new(8);
/// vec.fill(true);
/// ```
@ -135,103 +135,6 @@ impl From<&[u8]> for BitVec {
}
}
#[cfg(feature = "c_api")]
pub mod c_api {
use crate::{BitVec, CByteSlice, DataRef};
/// Creates a new `BitVec` instance.
/// The returned instance has to be freed with `bit_vec_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp2_bit_vec_new(size: usize) -> *mut BitVec {
Box::into_raw(Box::new(BitVec::new(size)))
}
/// Loads a `BitVec` from the provided data.
/// The returned instance has to be freed with `bit_vec_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp2_bit_vec_load(
data: *const u8,
data_length: usize,
) -> *mut BitVec {
let data = std::slice::from_raw_parts(data, data_length);
Box::into_raw(Box::new(BitVec::from(data)))
}
/// Clones a `BitVec`.
/// The returned instance has to be freed with `bit_vec_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp2_bit_vec_clone(
this: *const BitVec,
) -> *mut BitVec {
Box::into_raw(Box::new((*this).clone()))
}
/// Deallocates a `BitVec`.
///
/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
#[no_mangle]
pub unsafe extern "C" fn sp2_bit_vec_dealloc(this: *mut BitVec) {
_ = Box::from_raw(this);
}
/// Gets the value of a bit from the `BitVec`.
#[no_mangle]
pub unsafe extern "C" fn sp2_bit_vec_get(
this: *const BitVec,
index: usize,
) -> bool {
(*this).get(index)
}
/// Sets the value of a bit in the `BitVec`.
#[no_mangle]
pub unsafe extern "C" fn sp2_bit_vec_set(
this: *mut BitVec,
index: usize,
value: bool,
) -> bool {
(*this).set(index, value)
}
/// Sets the value of all bits in the `BitVec`.
#[no_mangle]
pub unsafe extern "C" fn sp2_bit_vec_fill(this: *mut BitVec, value: bool) {
(*this).fill(value)
}
/// Gets the length of the `BitVec` in bits.
#[no_mangle]
pub unsafe extern "C" fn sp2_bit_vec_len(this: *const BitVec) -> usize {
(*this).len()
}
/// Returns true if length is 0.
#[no_mangle]
pub unsafe extern "C" fn sp2_bit_vec_is_empty(this: *const BitVec) -> bool {
(*this).is_empty()
}
/// Gets an unsafe reference to the data of the `BitVec` instance.
///
/// ## Safety
///
/// The caller has to make sure to never access the returned memory after the `BitVec`
/// instance has been consumed or manually deallocated.
///
/// Reading and writing concurrently to either the original instance or the returned data will
/// result in undefined behavior.
#[no_mangle]
pub unsafe extern "C" fn sp2_bit_vec_unsafe_data_ref(
this: *mut BitVec,
) -> CByteSlice {
let data = (*this).data_ref_mut();
CByteSlice {
start: data.as_mut_ptr_range().start,
length: data.len(),
}
}
}
#[cfg(test)]
mod tests {
use crate::{BitVec, DataRef};

View file

@ -108,119 +108,6 @@ impl From<ByteGrid> for Vec<u8> {
}
}
#[cfg(feature = "c_api")]
pub mod c_api {
use crate::data_ref::DataRef;
use crate::grid::Grid;
use crate::{ByteGrid, CByteSlice};
/// Creates a new `ByteGrid` instance.
/// The returned instance has to be freed with `byte_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp2_byte_grid_new(
width: usize,
height: usize,
) -> *mut ByteGrid {
Box::into_raw(Box::new(ByteGrid::new(width, height)))
}
/// Loads a `ByteGrid` with the specified dimensions from the provided data.
/// The returned instance has to be freed with `byte_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp2_byte_grid_load(
width: usize,
height: usize,
data: *const u8,
data_length: usize,
) -> *mut ByteGrid {
let data = std::slice::from_raw_parts(data, data_length);
Box::into_raw(Box::new(ByteGrid::load(width, height, data)))
}
/// Clones a `ByteGrid`.
/// The returned instance has to be freed with `byte_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp2_byte_grid_clone(
this: *const ByteGrid,
) -> *mut ByteGrid {
Box::into_raw(Box::new((*this).clone()))
}
/// Deallocates a `ByteGrid`.
///
/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
#[no_mangle]
pub unsafe extern "C" fn sp2_byte_grid_dealloc(this: *mut ByteGrid) {
_ = Box::from_raw(this);
}
/// Get the current value at the specified position
#[no_mangle]
pub unsafe extern "C" fn sp2_byte_grid_get(
this: *const ByteGrid,
x: usize,
y: usize,
) -> u8 {
(*this).get(x, y)
}
/// Sets the current value at the specified position
#[no_mangle]
pub unsafe extern "C" fn sp2_byte_grid_set(
this: *mut ByteGrid,
x: usize,
y: usize,
value: u8,
) {
(*this).set(x, y, value);
}
/// Fills the whole `ByteGrid` with the specified value
#[no_mangle]
pub unsafe extern "C" fn sp2_byte_grid_fill(
this: *mut ByteGrid,
value: u8,
) {
(*this).fill(value);
}
/// Gets the width in pixels of the `ByteGrid` instance.
#[no_mangle]
pub unsafe extern "C" fn sp2_byte_grid_width(
this: *const ByteGrid,
) -> usize {
(*this).width
}
/// Gets the height in pixels of the `ByteGrid` instance.
#[no_mangle]
pub unsafe extern "C" fn sp2_byte_grid_height(
this: *const ByteGrid,
) -> usize {
(*this).height
}
/// Gets an unsafe reference to the data of the `ByteGrid` instance.
///
/// ## Safety
///
/// The caller has to make sure to never access the returned memory after the `ByteGrid`
/// instance has been consumed or manually deallocated.
///
/// Reading and writing concurrently to either the original instance or the returned data will
/// result in undefined behavior.
#[no_mangle]
pub unsafe extern "C" fn sp2_byte_grid_unsafe_data_ref(
this: *mut ByteGrid,
) -> CByteSlice {
let data = (*this).data_ref_mut();
CByteSlice {
start: data.as_mut_ptr_range().start,
length: data.len(),
}
}
}
#[cfg(test)]
mod tests {
use crate::{ByteGrid, DataRef, Grid};

View file

@ -391,179 +391,6 @@ impl Command {
}
}
#[cfg(feature = "c_api")]
pub mod c_api {
use std::ptr::null_mut;
use crate::{
BitVec, Brightness, ByteGrid, Command, CompressionCode, Offset, Origin,
Packet, PixelGrid,
};
/// Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.
///
/// Returns: pointer to command or NULL
#[no_mangle]
pub unsafe extern "C" fn sp2_command_try_from_packet(
packet: *mut Packet,
) -> *mut Command {
let packet = *Box::from_raw(packet);
match Command::try_from(packet) {
Err(_) => null_mut(),
Ok(command) => Box::into_raw(Box::new(command)),
}
}
/// Clones a `Command` instance
#[no_mangle]
pub unsafe extern "C" fn sp2_command_clone(
original: *const Command,
) -> *mut Command {
Box::into_raw(Box::new((*original).clone()))
}
/// Allocates a new `Command::Clear` instance
#[no_mangle]
pub unsafe extern "C" fn sp2_command_clear() -> *mut Command {
Box::into_raw(Box::new(Command::Clear))
}
/// Allocates a new `Command::HardReset` instance
#[no_mangle]
pub unsafe extern "C" fn sp2_command_hard_reset() -> *mut Command {
Box::into_raw(Box::new(Command::HardReset))
}
/// Allocates a new `Command::FadeOut` instance
#[no_mangle]
pub unsafe extern "C" fn sp2_command_fade_out() -> *mut Command {
Box::into_raw(Box::new(Command::FadeOut))
}
/// Allocates a new `Command::Brightness` instance
#[no_mangle]
pub unsafe extern "C" fn sp2_command_brightness(
brightness: Brightness,
) -> *mut Command {
Box::into_raw(Box::new(Command::Brightness(brightness)))
}
/// Allocates a new `Command::CharBrightness` instance.
/// The passed `ByteGrid` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp2_command_char_brightness(
x: usize,
y: usize,
byte_grid: *mut ByteGrid,
) -> *mut Command {
let byte_grid = *Box::from_raw(byte_grid);
Box::into_raw(Box::new(Command::CharBrightness(
Origin(x, y),
byte_grid,
)))
}
/// Allocates a new `Command::BitmapLinear` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp2_command_bitmap_linear(
offset: Offset,
bit_vec: *mut BitVec,
compression: CompressionCode,
) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinear(
offset,
bit_vec,
compression,
)))
}
/// Allocates a new `Command::BitmapLinearAnd` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp2_command_bitmap_linear_and(
offset: Offset,
bit_vec: *mut BitVec,
compression: CompressionCode,
) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinearAnd(
offset,
bit_vec,
compression,
)))
}
/// Allocates a new `Command::BitmapLinearOr` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp2_command_bitmap_linear_or(
offset: Offset,
bit_vec: *mut BitVec,
compression: CompressionCode,
) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinearOr(
offset,
bit_vec,
compression,
)))
}
/// Allocates a new `Command::BitmapLinearXor` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp2_command_bitmap_linear_xor(
offset: Offset,
bit_vec: *mut BitVec,
compression: CompressionCode,
) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinearXor(
offset,
bit_vec,
compression,
)))
}
/// Allocates a new `Command::Cp437Data` instance.
/// The passed `ByteGrid` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp2_command_cp437_data(
x: usize,
y: usize,
byte_grid: *mut ByteGrid,
) -> *mut Command {
let byte_grid = *Box::from_raw(byte_grid);
Box::into_raw(Box::new(Command::Cp437Data(Origin(x, y), byte_grid)))
}
/// Allocates a new `Command::BitmapLinearWin` instance.
/// The passed `PixelGrid` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp2_command_bitmap_linear_win(
x: usize,
y: usize,
byte_grid: *mut PixelGrid,
compression_code: CompressionCode,
) -> *mut Command {
let byte_grid = *Box::from_raw(byte_grid);
Box::into_raw(Box::new(Command::BitmapLinearWin(
Origin(x, y),
byte_grid,
compression_code,
)))
}
/// Deallocates a `Command`. Note that connection_send does this implicitly, so you only need
/// to do this if you use the library for parsing commands.
#[no_mangle]
pub unsafe extern "C" fn sp2_command_dealloc(ptr: *mut Command) {
_ = Box::from_raw(ptr);
}
}
#[cfg(test)]
mod tests {
use crate::command::TryFromPacketError;

View file

@ -10,8 +10,6 @@ pub struct Connection {
socket: UdpSocket,
}
impl Connection {
/// Open a new UDP socket and connect to the provided host.
///
@ -23,7 +21,7 @@ impl Connection {
///
/// # Examples
/// ```rust
/// let connection = servicepoint2::Connection::open("172.23.42.29:2342")
/// let connection = servicepoint::Connection::open("172.23.42.29:2342")
/// .expect("connection failed");
/// ```
pub fn open(addr: impl ToSocketAddrs + Debug) -> std::io::Result<Self> {
@ -48,8 +46,8 @@ impl Connection {
/// # Examples
///
/// ```rust
/// use servicepoint2::{Command, CompressionCode, Grid, PixelGrid};
/// let connection = servicepoint2::Connection::open("172.23.42.29:2342")
/// use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
/// let connection = servicepoint::Connection::open("172.23.42.29:2342")
/// .expect("connection failed");
///
/// // turn off all pixels
@ -61,10 +59,13 @@ impl Connection {
/// pixels.fill(true);
///
/// // send pixels to display
/// connection.send(Command::BitmapLinearWin(servicepoint2::Origin(0, 0), pixels, CompressionCode::Uncompressed))
/// connection.send(Command::BitmapLinearWin(servicepoint::Origin(0, 0), pixels, CompressionCode::Uncompressed))
/// .expect("send failed");
/// ```
pub fn send(&self, packet: impl Into<Packet>) -> Result<(), std::io::Error> {
pub fn send(
&self,
packet: impl Into<Packet>,
) -> Result<(), std::io::Error> {
let packet = packet.into();
debug!("sending {packet:?}");
let data: Vec<u8> = packet.into();
@ -72,46 +73,3 @@ impl Connection {
Ok(())
}
}
#[cfg(feature = "c_api")]
pub mod c_api {
use std::ffi::{c_char, CStr};
use std::ptr::null_mut;
use crate::{Connection, Packet};
/// Creates a new instance of Connection.
/// The returned instance has to be deallocated with `connection_dealloc`.
///
/// returns: NULL if connection fails or connected instance
///
/// Panics: bad string encoding
#[no_mangle]
pub unsafe extern "C" fn sp2_connection_open(
host: *const c_char,
) -> *mut Connection {
let host = CStr::from_ptr(host).to_str().expect("Bad encoding");
let connection = match Connection::open(host) {
Err(_) => return null_mut(),
Ok(value) => value,
};
Box::into_raw(Box::new(connection))
}
/// Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.
#[no_mangle]
pub unsafe extern "C" fn sp2_connection_send(
connection: *const Connection,
command_ptr: *mut Packet,
) -> bool {
let packet = Box::from_raw(command_ptr);
(*connection).send(*packet).is_ok()
}
/// Closes and deallocates a connection instance
#[no_mangle]
pub unsafe extern "C" fn sp2_connection_dealloc(ptr: *mut Connection) {
_ = Box::from_raw(ptr);
}
}

View file

@ -35,7 +35,7 @@ pub trait Grid<T> {
/// # Examples
/// To avoid boxing, this example is using the concrete type `ByteGrid`.
/// ```
/// use servicepoint2::{ByteGrid, Grid};
/// use servicepoint::{ByteGrid, Grid};
/// fn split(grid: ByteGrid) -> (ByteGrid, ByteGrid) {
/// assert!(grid.width() >= 2);
/// let split_x = grid.width() / 2;

View file

@ -2,8 +2,6 @@ use std::time::Duration;
pub use crate::bit_vec::BitVec;
pub use crate::byte_grid::ByteGrid;
#[cfg(feature = "c_api")]
pub use crate::c_slice::CByteSlice;
pub use crate::command::{Brightness, Command, Offset, Origin};
pub use crate::compression_code::CompressionCode;
pub use crate::connection::Connection;
@ -14,7 +12,6 @@ pub use crate::pixel_grid::PixelGrid;
mod bit_vec;
mod byte_grid;
mod c_slice;
mod command;
mod command_code;
mod compression;

View file

@ -58,46 +58,6 @@ impl TryFrom<&[u8]> for Packet {
}
}
#[cfg(feature = "c_api")]
mod c_api {
use std::ptr::null_mut;
use crate::{Command, Packet};
/// Turns a `Command` into a `Packet`. The command gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp2_packet_from_command(
command: *mut Command,
) -> *mut Packet {
let command = *Box::from_raw(command);
let packet = command.into();
Box::into_raw(Box::new(packet))
}
/// Tries to load a `Packet` from the passed array with the specified length.
///
/// returns: NULL in case of an error, pointer to the allocated packet otherwise
#[no_mangle]
pub unsafe extern "C" fn sp2_packet_try_load(
data: *const u8,
length: usize,
) -> *mut Packet {
let data = std::slice::from_raw_parts(data, length);
match Packet::try_from(data) {
Err(_) => null_mut(),
Ok(packet) => Box::into_raw(Box::new(packet)),
}
}
/// Deallocates a `Packet`.
///
/// Note: do not call this if the instance has been consumed in another way, e.g. by sending it.
#[no_mangle]
pub unsafe extern "C" fn sp2_packet_dealloc(this: *mut Packet) {
_ = Box::from_raw(this)
}
}
#[cfg(test)]
mod tests {
use crate::{Header, Packet};

View file

@ -127,118 +127,6 @@ impl From<PixelGrid> for Vec<u8> {
}
}
#[cfg(feature = "c_api")]
pub mod c_api {
use crate::c_slice::CByteSlice;
use crate::{DataRef, Grid, PixelGrid};
/// Creates a new `PixelGrid` instance.
/// The returned instance has to be freed with `pixel_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp2_pixel_grid_new(
width: usize,
height: usize,
) -> *mut PixelGrid {
Box::into_raw(Box::new(PixelGrid::new(width, height)))
}
/// Loads a `PixelGrid` with the specified dimensions from the provided data.
/// The returned instance has to be freed with `pixel_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp2_pixel_grid_load(
width: usize,
height: usize,
data: *const u8,
data_length: usize,
) -> *mut PixelGrid {
let data = std::slice::from_raw_parts(data, data_length);
Box::into_raw(Box::new(PixelGrid::load(width, height, data)))
}
/// Clones a `PixelGrid`.
/// The returned instance has to be freed with `pixel_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp2_pixel_grid_clone(
this: *const PixelGrid,
) -> *mut PixelGrid {
Box::into_raw(Box::new((*this).clone()))
}
/// Deallocates a `PixelGrid`.
///
/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
#[no_mangle]
pub unsafe extern "C" fn sp2_pixel_grid_dealloc(this: *mut PixelGrid) {
_ = Box::from_raw(this);
}
/// Get the current value at the specified position
#[no_mangle]
pub unsafe extern "C" fn sp2_pixel_grid_get(
this: *const PixelGrid,
x: usize,
y: usize,
) -> bool {
(*this).get(x, y)
}
/// Sets the current value at the specified position
#[no_mangle]
pub unsafe extern "C" fn sp2_pixel_grid_set(
this: *mut PixelGrid,
x: usize,
y: usize,
value: bool,
) {
(*this).set(x, y, value);
}
/// Fills the whole `PixelGrid` with the specified value
#[no_mangle]
pub unsafe extern "C" fn sp2_pixel_grid_fill(
this: *mut PixelGrid,
value: bool,
) {
(*this).fill(value);
}
/// Gets the width in pixels of the `PixelGrid` instance.
#[no_mangle]
pub unsafe extern "C" fn sp2_pixel_grid_width(
this: *const PixelGrid,
) -> usize {
(*this).width
}
/// Gets the height in pixels of the `PixelGrid` instance.
#[no_mangle]
pub unsafe extern "C" fn sp2_pixel_grid_height(
this: *const PixelGrid,
) -> usize {
(*this).height
}
/// Gets an unsafe reference to the data of the `PixelGrid` instance.
///
/// ## Safety
///
/// The caller has to make sure to never access the returned memory after the `PixelGrid`
/// instance has been consumed or manually deallocated.
///
/// Reading and writing concurrently to either the original instance or the returned data will
/// result in undefined behavior.
#[no_mangle]
pub unsafe extern "C" fn sp2_pixel_grid_unsafe_data_ref(
this: *mut PixelGrid,
) -> CByteSlice {
let data = (*this).data_ref_mut();
CByteSlice {
start: data.as_mut_ptr_range().start,
length: data.len(),
}
}
}
#[cfg(test)]
mod tests {
use crate::{DataRef, Grid, PixelGrid};

View file

@ -0,0 +1,22 @@
[package]
name = "servicepoint_binding_c"
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"
repository = "https://github.com/cccb/servicepoint"
readme = "README.md"
links = "servicepoint"
[lib]
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
cbindgen = "0.26.0"
[dependencies.servicepoint]
version = "0.5.0"
path = "../servicepoint"
features = ["all_compressions"]

View file

@ -0,0 +1,63 @@
# servicepoint_binding_c
[![crates.io](https://img.shields.io/crates/v/servicepoint_binding_c.svg)](https://crates.io/crates/servicepoint)
[![Crates.io Total Downloads](https://img.shields.io/crates/d/servicepoint_binding_c)](https://crates.io/crates/servicepoint)
[![docs.rs](https://img.shields.io/docsrs/servicepoint_binding_c)](https://docs.rs/servicepoint/latest/servicepoint/)
[![GPLv3 licensed](https://img.shields.io/crates/l/servicepoint_binding_c)](../../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) {
sp2_Connection *connection = sp2_connection_open("localhost:2342");
if (connection == NULL)
return 1;
sp2_PixelGrid *pixels = sp2_pixel_grid_new(sp2_PIXEL_WIDTH, sp2_PIXEL_HEIGHT);
sp2_pixel_grid_fill(pixels, true);
sp2_Command *command = sp2_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
sp2_Packet *packet = sp2_packet_from_command(command);
if (!sp2_connection_send(connection, packet))
return 1;
sp2_connection_dealloc(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: `sp2_` \<struct_name\> \<rust name\>.
- Use the rust documentation.
- Instances get consumed in the same way they do when writing rust / C# 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.
## Everything else
Look at the main project [README](https://github.com/cccb/servicepoint/blob/main/README.md) for further information.

View file

@ -0,0 +1,27 @@
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}");
}
}

View file

@ -19,14 +19,18 @@ sort_by = "Name"
usize_is_size_t = true
[defines]
"feature = compression_zlib" = "SP2_FEATURE_compression_zlib"
"feature = compression_bzip2" = "SP2_FEATURE_compression_bzip2"
"feature = compression_lzma" = "SP2_FEATURE_compression_lzma"
"feature = compression_zstd" = "SP2_FEATURE_compression_zstd"
#"feature = compression_zlib" = "SP_FEATURE_compression_zlib"
#"feature = compression_bzip2" = "SP_FEATURE_compression_bzip2"
#"feature = compression_lzma" = "SP_FEATURE_compression_lzma"
#"feature = compression_zstd" = "SP_FEATURE_compression_zstd"
[export]
prefix = "sp2_"
prefix = "sp_"
[parse]
parse_deps = true
include = ["servicepoint"]
extra_bindings = ["servicepoint"]
[parse.expand]
features = ["c-api"]
all_features = true
#all_features = true

View file

@ -0,0 +1,14 @@
[package]
name = "lang_c"
version = "0.1.0"
edition = "2021"
publish = false
[lib]
test = false
[build-dependencies]
cc = "1.0"
[dependencies]
servicepoint_binding_c = { path = "../.." }

View file

@ -0,0 +1,33 @@
CC := gcc
THIS_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
REPO_ROOT := $(THIS_DIR)/../..
build: out/lang_c
clean:
rm -r out
rm include/servicepoint.h
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: ;

View file

@ -0,0 +1,16 @@
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.compile("lang_c");
}

View file

@ -9,95 +9,87 @@
/**
* pixel count on whole screen
*/
#define sp2_PIXEL_COUNT (sp2_PIXEL_WIDTH * sp2_PIXEL_HEIGHT)
#define sp_PIXEL_COUNT (sp_PIXEL_WIDTH * sp_PIXEL_HEIGHT)
/**
* screen height in pixels
*/
#define sp2_PIXEL_HEIGHT (sp2_TILE_HEIGHT * sp2_TILE_SIZE)
#define sp_PIXEL_HEIGHT (sp_TILE_HEIGHT * sp_TILE_SIZE)
/**
* screen width in pixels
*/
#define sp2_PIXEL_WIDTH (sp2_TILE_WIDTH * sp2_TILE_SIZE)
#define sp_PIXEL_WIDTH (sp_TILE_WIDTH * sp_TILE_SIZE)
/**
* tile count in the y-direction
*/
#define sp2_TILE_HEIGHT 20
#define sp_TILE_HEIGHT 20
/**
* size of a single tile in one dimension
*/
#define sp2_TILE_SIZE 8
#define sp_TILE_SIZE 8
/**
* tile count in the x-direction
*/
#define sp2_TILE_WIDTH 56
#define sp_TILE_WIDTH 56
/**
* Specifies the kind of compression to use. Availability depends on features.
*/
enum sp2_CompressionCode
enum sp_CompressionCode
#ifdef __cplusplus
: uint16_t
#endif // __cplusplus
{
Uncompressed = 0,
#if defined(SP2_FEATURE_compression_zlib)
Zlib = 26490,
#endif
#if defined(SP2_FEATURE_compression_bzip2)
Bzip2 = 25210,
#endif
#if defined(SP2_FEATURE_compression_lzma)
Lzma = 27770,
#endif
#if defined(SP2_FEATURE_compression_zstd)
Zstd = 31347,
#endif
};
#ifndef __cplusplus
typedef uint16_t sp2_CompressionCode;
typedef uint16_t sp_CompressionCode;
#endif // __cplusplus
/**
* A vector of bits
*/
typedef struct sp2_BitVec sp2_BitVec;
typedef struct sp_BitVec sp_BitVec;
/**
* A 2D grid of bytes
*/
typedef struct sp2_ByteGrid sp2_ByteGrid;
typedef struct sp_ByteGrid sp_ByteGrid;
/**
* A command to send to the display.
*/
typedef struct sp2_Command sp2_Command;
typedef struct sp_Command sp_Command;
/**
* A connection to the display.
*/
typedef struct sp2_Connection sp2_Connection;
typedef struct sp_Connection sp_Connection;
/**
* The raw packet. Should probably not be used directly.
*/
typedef struct sp2_Packet sp2_Packet;
typedef struct sp_Packet sp_Packet;
/**
* A grid of pixels stored in packed bytes.
*/
typedef struct sp2_PixelGrid sp2_PixelGrid;
typedef struct sp_PixelGrid sp_PixelGrid;
/**
* Represents a span of memory (`&mut [u8]` ) as a struct usable by C code.
*
* Usage of this type is inherently unsafe.
*/
typedef struct sp2_CByteSlice {
typedef struct sp_CByteSlice {
/**
* The start address of the memory
*/
@ -106,17 +98,17 @@ typedef struct sp2_CByteSlice {
* The amount of memory in bytes
*/
size_t length;
} sp2_CByteSlice;
} sp_CByteSlice;
/**
* Type alias for documenting the meaning of the u16 in enum values
*/
typedef size_t sp2_Offset;
typedef size_t sp_Offset;
/**
* Type alias for documenting the meaning of the u16 in enum values
*/
typedef uint8_t sp2_Brightness;
typedef uint8_t sp_Brightness;
#ifdef __cplusplus
extern "C" {
@ -126,51 +118,51 @@ extern "C" {
* Clones a `BitVec`.
* The returned instance has to be freed with `bit_vec_dealloc`.
*/
struct sp2_BitVec *sp2_bit_vec_clone(const struct sp2_BitVec *this_);
struct sp_BitVec *sp_bit_vec_clone(const struct sp_BitVec *this_);
/**
* Deallocates a `BitVec`.
*
* Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
*/
void sp2_bit_vec_dealloc(struct sp2_BitVec *this_);
void sp_bit_vec_dealloc(struct sp_BitVec *this_);
/**
* Sets the value of all bits in the `BitVec`.
*/
void sp2_bit_vec_fill(struct sp2_BitVec *this_, bool value);
void sp_bit_vec_fill(struct sp_BitVec *this_, bool value);
/**
* Gets the value of a bit from the `BitVec`.
*/
bool sp2_bit_vec_get(const struct sp2_BitVec *this_, size_t index);
bool sp_bit_vec_get(const struct sp_BitVec *this_, size_t index);
/**
* Returns true if length is 0.
*/
bool sp2_bit_vec_is_empty(const struct sp2_BitVec *this_);
bool sp_bit_vec_is_empty(const struct sp_BitVec *this_);
/**
* Gets the length of the `BitVec` in bits.
*/
size_t sp2_bit_vec_len(const struct sp2_BitVec *this_);
size_t sp_bit_vec_len(const struct sp_BitVec *this_);
/**
* Loads a `BitVec` from the provided data.
* The returned instance has to be freed with `bit_vec_dealloc`.
*/
struct sp2_BitVec *sp2_bit_vec_load(const uint8_t *data, size_t data_length);
struct sp_BitVec *sp_bit_vec_load(const uint8_t *data, size_t data_length);
/**
* Creates a new `BitVec` instance.
* The returned instance has to be freed with `bit_vec_dealloc`.
*/
struct sp2_BitVec *sp2_bit_vec_new(size_t size);
struct sp_BitVec *sp_bit_vec_new(size_t size);
/**
* Sets the value of a bit in the `BitVec`.
*/
bool sp2_bit_vec_set(struct sp2_BitVec *this_, size_t index, bool value);
bool sp_bit_vec_set(struct sp_BitVec *this_, size_t index, bool value);
/**
* Gets an unsafe reference to the data of the `BitVec` instance.
@ -183,58 +175,58 @@ bool sp2_bit_vec_set(struct sp2_BitVec *this_, size_t index, bool value);
* Reading and writing concurrently to either the original instance or the returned data will
* result in undefined behavior.
*/
struct sp2_CByteSlice sp2_bit_vec_unsafe_data_ref(struct sp2_BitVec *this_);
struct sp_CByteSlice sp_bit_vec_unsafe_data_ref(struct sp_BitVec *this_);
/**
* Clones a `ByteGrid`.
* The returned instance has to be freed with `byte_grid_dealloc`.
*/
struct sp2_ByteGrid *sp2_byte_grid_clone(const struct sp2_ByteGrid *this_);
struct sp_ByteGrid *sp_byte_grid_clone(const struct sp_ByteGrid *this_);
/**
* Deallocates a `ByteGrid`.
*
* Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
*/
void sp2_byte_grid_dealloc(struct sp2_ByteGrid *this_);
void sp_byte_grid_dealloc(struct sp_ByteGrid *this_);
/**
* Fills the whole `ByteGrid` with the specified value
*/
void sp2_byte_grid_fill(struct sp2_ByteGrid *this_, uint8_t value);
void sp_byte_grid_fill(struct sp_ByteGrid *this_, uint8_t value);
/**
* Get the current value at the specified position
*/
uint8_t sp2_byte_grid_get(const struct sp2_ByteGrid *this_, size_t x, size_t y);
uint8_t sp_byte_grid_get(const struct sp_ByteGrid *this_, size_t x, size_t y);
/**
* Gets the height in pixels of the `ByteGrid` instance.
*/
size_t sp2_byte_grid_height(const struct sp2_ByteGrid *this_);
size_t sp_byte_grid_height(const struct sp_ByteGrid *this_);
/**
* Loads a `ByteGrid` with the specified dimensions from the provided data.
* The returned instance has to be freed with `byte_grid_dealloc`.
*/
struct sp2_ByteGrid *sp2_byte_grid_load(size_t width,
size_t height,
const uint8_t *data,
size_t data_length);
struct sp_ByteGrid *sp_byte_grid_load(size_t width,
size_t height,
const uint8_t *data,
size_t data_length);
/**
* Creates a new `ByteGrid` instance.
* The returned instance has to be freed with `byte_grid_dealloc`.
*/
struct sp2_ByteGrid *sp2_byte_grid_new(size_t width, size_t height);
struct sp_ByteGrid *sp_byte_grid_new(size_t width, size_t height);
/**
* Sets the current value at the specified position
*/
void sp2_byte_grid_set(struct sp2_ByteGrid *this_,
size_t x,
size_t y,
uint8_t value);
void sp_byte_grid_set(struct sp_ByteGrid *this_,
size_t x,
size_t y,
uint8_t value);
/**
* Gets an unsafe reference to the data of the `ByteGrid` instance.
@ -247,112 +239,112 @@ void sp2_byte_grid_set(struct sp2_ByteGrid *this_,
* Reading and writing concurrently to either the original instance or the returned data will
* result in undefined behavior.
*/
struct sp2_CByteSlice sp2_byte_grid_unsafe_data_ref(struct sp2_ByteGrid *this_);
struct sp_CByteSlice sp_byte_grid_unsafe_data_ref(struct sp_ByteGrid *this_);
/**
* Gets the width in pixels of the `ByteGrid` instance.
*/
size_t sp2_byte_grid_width(const struct sp2_ByteGrid *this_);
size_t sp_byte_grid_width(const struct sp_ByteGrid *this_);
/**
* Allocates a new `Command::BitmapLinear` instance.
* The passed `BitVec` gets deallocated in the process.
*/
struct sp2_Command *sp2_command_bitmap_linear(sp2_Offset offset,
struct sp2_BitVec *bit_vec,
sp2_CompressionCode compression);
struct sp_Command *sp_command_bitmap_linear(sp_Offset offset,
struct sp_BitVec *bit_vec,
sp_CompressionCode compression);
/**
* Allocates a new `Command::BitmapLinearAnd` instance.
* The passed `BitVec` gets deallocated in the process.
*/
struct sp2_Command *sp2_command_bitmap_linear_and(sp2_Offset offset,
struct sp2_BitVec *bit_vec,
sp2_CompressionCode compression);
struct sp_Command *sp_command_bitmap_linear_and(sp_Offset offset,
struct sp_BitVec *bit_vec,
sp_CompressionCode compression);
/**
* Allocates a new `Command::BitmapLinearOr` instance.
* The passed `BitVec` gets deallocated in the process.
*/
struct sp2_Command *sp2_command_bitmap_linear_or(sp2_Offset offset,
struct sp2_BitVec *bit_vec,
sp2_CompressionCode compression);
struct sp_Command *sp_command_bitmap_linear_or(sp_Offset offset,
struct sp_BitVec *bit_vec,
sp_CompressionCode compression);
/**
* Allocates a new `Command::BitmapLinearWin` instance.
* The passed `PixelGrid` gets deallocated in the process.
*/
struct sp2_Command *sp2_command_bitmap_linear_win(size_t x,
size_t y,
struct sp2_PixelGrid *byte_grid,
sp2_CompressionCode compression_code);
struct sp_Command *sp_command_bitmap_linear_win(size_t x,
size_t y,
struct sp_PixelGrid *byte_grid,
sp_CompressionCode compression_code);
/**
* Allocates a new `Command::BitmapLinearXor` instance.
* The passed `BitVec` gets deallocated in the process.
*/
struct sp2_Command *sp2_command_bitmap_linear_xor(sp2_Offset offset,
struct sp2_BitVec *bit_vec,
sp2_CompressionCode compression);
struct sp_Command *sp_command_bitmap_linear_xor(sp_Offset offset,
struct sp_BitVec *bit_vec,
sp_CompressionCode compression);
/**
* Allocates a new `Command::Brightness` instance
*/
struct sp2_Command *sp2_command_brightness(sp2_Brightness brightness);
struct sp_Command *sp_command_brightness(sp_Brightness brightness);
/**
* Allocates a new `Command::CharBrightness` instance.
* The passed `ByteGrid` gets deallocated in the process.
*/
struct sp2_Command *sp2_command_char_brightness(size_t x,
size_t y,
struct sp2_ByteGrid *byte_grid);
struct sp_Command *sp_command_char_brightness(size_t x,
size_t y,
struct sp_ByteGrid *byte_grid);
/**
* Allocates a new `Command::Clear` instance
*/
struct sp2_Command *sp2_command_clear(void);
struct sp_Command *sp_command_clear(void);
/**
* Clones a `Command` instance
*/
struct sp2_Command *sp2_command_clone(const struct sp2_Command *original);
struct sp_Command *sp_command_clone(const struct sp_Command *original);
/**
* Allocates a new `Command::Cp437Data` instance.
* The passed `ByteGrid` gets deallocated in the process.
*/
struct sp2_Command *sp2_command_cp437_data(size_t x,
size_t y,
struct sp2_ByteGrid *byte_grid);
struct sp_Command *sp_command_cp437_data(size_t x,
size_t y,
struct sp_ByteGrid *byte_grid);
/**
* Deallocates a `Command`. Note that connection_send does this implicitly, so you only need
* to do this if you use the library for parsing commands.
*/
void sp2_command_dealloc(struct sp2_Command *ptr);
void sp_command_dealloc(struct sp_Command *ptr);
/**
* Allocates a new `Command::FadeOut` instance
*/
struct sp2_Command *sp2_command_fade_out(void);
struct sp_Command *sp_command_fade_out(void);
/**
* Allocates a new `Command::HardReset` instance
*/
struct sp2_Command *sp2_command_hard_reset(void);
struct sp_Command *sp_command_hard_reset(void);
/**
* Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.
*
* Returns: pointer to command or NULL
*/
struct sp2_Command *sp2_command_try_from_packet(struct sp2_Packet *packet);
struct sp_Command *sp_command_try_from_packet(struct sp_Packet *packet);
/**
* Closes and deallocates a connection instance
*/
void sp2_connection_dealloc(struct sp2_Connection *ptr);
void sp_connection_dealloc(struct sp_Connection *ptr);
/**
* Creates a new instance of Connection.
@ -362,83 +354,83 @@ void sp2_connection_dealloc(struct sp2_Connection *ptr);
*
* Panics: bad string encoding
*/
struct sp2_Connection *sp2_connection_open(const char *host);
struct sp_Connection *sp_connection_open(const char *host);
/**
* Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.
*/
bool sp2_connection_send(const struct sp2_Connection *connection,
struct sp2_Packet *command_ptr);
bool sp_connection_send(const struct sp_Connection *connection,
struct sp_Packet *command_ptr);
/**
* Deallocates a `Packet`.
*
* Note: do not call this if the instance has been consumed in another way, e.g. by sending it.
*/
void sp2_packet_dealloc(struct sp2_Packet *this_);
void sp_packet_dealloc(struct sp_Packet *this_);
/**
* Turns a `Command` into a `Packet`. The command gets deallocated in the process.
*/
struct sp2_Packet *sp2_packet_from_command(struct sp2_Command *command);
struct sp_Packet *sp_packet_from_command(struct sp_Command *command);
/**
* Tries to load a `Packet` from the passed array with the specified length.
*
* returns: NULL in case of an error, pointer to the allocated packet otherwise
*/
struct sp2_Packet *sp2_packet_try_load(const uint8_t *data, size_t length);
struct sp_Packet *sp_packet_try_load(const uint8_t *data, size_t length);
/**
* Clones a `PixelGrid`.
* The returned instance has to be freed with `pixel_grid_dealloc`.
*/
struct sp2_PixelGrid *sp2_pixel_grid_clone(const struct sp2_PixelGrid *this_);
struct sp_PixelGrid *sp_pixel_grid_clone(const struct sp_PixelGrid *this_);
/**
* Deallocates a `PixelGrid`.
*
* Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
*/
void sp2_pixel_grid_dealloc(struct sp2_PixelGrid *this_);
void sp_pixel_grid_dealloc(struct sp_PixelGrid *this_);
/**
* Fills the whole `PixelGrid` with the specified value
*/
void sp2_pixel_grid_fill(struct sp2_PixelGrid *this_, bool value);
void sp_pixel_grid_fill(struct sp_PixelGrid *this_, bool value);
/**
* Get the current value at the specified position
*/
bool sp2_pixel_grid_get(const struct sp2_PixelGrid *this_, size_t x, size_t y);
bool sp_pixel_grid_get(const struct sp_PixelGrid *this_, size_t x, size_t y);
/**
* Gets the height in pixels of the `PixelGrid` instance.
*/
size_t sp2_pixel_grid_height(const struct sp2_PixelGrid *this_);
size_t sp_pixel_grid_height(const struct sp_PixelGrid *this_);
/**
* Loads a `PixelGrid` with the specified dimensions from the provided data.
* The returned instance has to be freed with `pixel_grid_dealloc`.
*/
struct sp2_PixelGrid *sp2_pixel_grid_load(size_t width,
size_t height,
const uint8_t *data,
size_t data_length);
struct sp_PixelGrid *sp_pixel_grid_load(size_t width,
size_t height,
const uint8_t *data,
size_t data_length);
/**
* Creates a new `PixelGrid` instance.
* The returned instance has to be freed with `pixel_grid_dealloc`.
*/
struct sp2_PixelGrid *sp2_pixel_grid_new(size_t width, size_t height);
struct sp_PixelGrid *sp_pixel_grid_new(size_t width, size_t height);
/**
* Sets the current value at the specified position
*/
void sp2_pixel_grid_set(struct sp2_PixelGrid *this_,
size_t x,
size_t y,
bool value);
void sp_pixel_grid_set(struct sp_PixelGrid *this_,
size_t x,
size_t y,
bool value);
/**
* Gets an unsafe reference to the data of the `PixelGrid` instance.
@ -451,12 +443,12 @@ void sp2_pixel_grid_set(struct sp2_PixelGrid *this_,
* Reading and writing concurrently to either the original instance or the returned data will
* result in undefined behavior.
*/
struct sp2_CByteSlice sp2_pixel_grid_unsafe_data_ref(struct sp2_PixelGrid *this_);
struct sp_CByteSlice sp_pixel_grid_unsafe_data_ref(struct sp_PixelGrid *this_);
/**
* Gets the width in pixels of the `PixelGrid` instance.
*/
size_t sp2_pixel_grid_width(const struct sp2_PixelGrid *this_);
size_t sp_pixel_grid_width(const struct sp_PixelGrid *this_);
#ifdef __cplusplus
} // extern "C"

View file

@ -0,0 +1,19 @@
#include <stdio.h>
#include "servicepoint.h"
int main(void) {
sp_Connection *connection = sp_connection_open("localhost:2342");
if (connection == NULL)
return 1;
sp_PixelGrid *pixels = sp_pixel_grid_new(sp_PIXEL_WIDTH, sp_PIXEL_HEIGHT);
sp_pixel_grid_fill(pixels, true);
sp_Command *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
sp_Packet *packet = sp_packet_from_command(command);
if (!sp_connection_send(connection, packet))
return 1;
sp_connection_dealloc(connection);
return 0;
}

View file

@ -0,0 +1,94 @@
pub use servicepoint::BitVec;
use servicepoint::DataRef;
use crate::c_slice::CByteSlice;
/// Creates a new `BitVec` instance.
/// The returned instance has to be freed with `bit_vec_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp_bit_vec_new(size: usize) -> *mut BitVec {
Box::into_raw(Box::new(BitVec::new(size)))
}
/// Loads a `BitVec` from the provided data.
/// The returned instance has to be freed with `bit_vec_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp_bit_vec_load(
data: *const u8,
data_length: usize,
) -> *mut BitVec {
let data = std::slice::from_raw_parts(data, data_length);
Box::into_raw(Box::new(BitVec::from(data)))
}
/// Clones a `BitVec`.
/// The returned instance has to be freed with `bit_vec_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp_bit_vec_clone(this: *const BitVec) -> *mut BitVec {
Box::into_raw(Box::new((*this).clone()))
}
/// Deallocates a `BitVec`.
///
/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
#[no_mangle]
pub unsafe extern "C" fn sp_bit_vec_dealloc(this: *mut BitVec) {
_ = Box::from_raw(this);
}
/// Gets the value of a bit from the `BitVec`.
#[no_mangle]
pub unsafe extern "C" fn sp_bit_vec_get(
this: *const BitVec,
index: usize,
) -> bool {
(*this).get(index)
}
/// Sets the value of a bit in the `BitVec`.
#[no_mangle]
pub unsafe extern "C" fn sp_bit_vec_set(
this: *mut BitVec,
index: usize,
value: bool,
) -> bool {
(*this).set(index, value)
}
/// Sets the value of all bits in the `BitVec`.
#[no_mangle]
pub unsafe extern "C" fn sp_bit_vec_fill(this: *mut BitVec, value: bool) {
(*this).fill(value)
}
/// Gets the length of the `BitVec` in bits.
#[no_mangle]
pub unsafe extern "C" fn sp_bit_vec_len(this: *const BitVec) -> usize {
(*this).len()
}
/// Returns true if length is 0.
#[no_mangle]
pub unsafe extern "C" fn sp_bit_vec_is_empty(this: *const BitVec) -> bool {
(*this).is_empty()
}
/// Gets an unsafe reference to the data of the `BitVec` instance.
///
/// ## Safety
///
/// The caller has to make sure to never access the returned memory after the `BitVec`
/// instance has been consumed or manually deallocated.
///
/// Reading and writing concurrently to either the original instance or the returned data will
/// result in undefined behavior.
#[no_mangle]
pub unsafe extern "C" fn sp_bit_vec_unsafe_data_ref(
this: *mut BitVec,
) -> CByteSlice {
let data = (*this).data_ref_mut();
CByteSlice {
start: data.as_mut_ptr_range().start,
length: data.len(),
}
}

View file

@ -0,0 +1,103 @@
pub use servicepoint::ByteGrid;
use servicepoint::{DataRef, Grid};
use crate::c_slice::CByteSlice;
/// Creates a new `ByteGrid` instance.
/// The returned instance has to be freed with `byte_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp_byte_grid_new(
width: usize,
height: usize,
) -> *mut ByteGrid {
Box::into_raw(Box::new(ByteGrid::new(width, height)))
}
/// Loads a `ByteGrid` with the specified dimensions from the provided data.
/// The returned instance has to be freed with `byte_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp_byte_grid_load(
width: usize,
height: usize,
data: *const u8,
data_length: usize,
) -> *mut ByteGrid {
let data = std::slice::from_raw_parts(data, data_length);
Box::into_raw(Box::new(ByteGrid::load(width, height, data)))
}
/// Clones a `ByteGrid`.
/// The returned instance has to be freed with `byte_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp_byte_grid_clone(
this: *const ByteGrid,
) -> *mut ByteGrid {
Box::into_raw(Box::new((*this).clone()))
}
/// Deallocates a `ByteGrid`.
///
/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
#[no_mangle]
pub unsafe extern "C" fn sp_byte_grid_dealloc(this: *mut ByteGrid) {
_ = Box::from_raw(this);
}
/// Get the current value at the specified position
#[no_mangle]
pub unsafe extern "C" fn sp_byte_grid_get(
this: *const ByteGrid,
x: usize,
y: usize,
) -> u8 {
(*this).get(x, y)
}
/// Sets the current value at the specified position
#[no_mangle]
pub unsafe extern "C" fn sp_byte_grid_set(
this: *mut ByteGrid,
x: usize,
y: usize,
value: u8,
) {
(*this).set(x, y, value);
}
/// Fills the whole `ByteGrid` with the specified value
#[no_mangle]
pub unsafe extern "C" fn sp_byte_grid_fill(this: *mut ByteGrid, value: u8) {
(*this).fill(value);
}
/// Gets the width in pixels of the `ByteGrid` instance.
#[no_mangle]
pub unsafe extern "C" fn sp_byte_grid_width(this: *const ByteGrid) -> usize {
(*this).width()
}
/// Gets the height in pixels of the `ByteGrid` instance.
#[no_mangle]
pub unsafe extern "C" fn sp_byte_grid_height(this: *const ByteGrid) -> usize {
(*this).height()
}
/// Gets an unsafe reference to the data of the `ByteGrid` instance.
///
/// ## Safety
///
/// The caller has to make sure to never access the returned memory after the `ByteGrid`
/// instance has been consumed or manually deallocated.
///
/// Reading and writing concurrently to either the original instance or the returned data will
/// result in undefined behavior.
#[no_mangle]
pub unsafe extern "C" fn sp_byte_grid_unsafe_data_ref(
this: *mut ByteGrid,
) -> CByteSlice {
let data = (*this).data_ref_mut();
CByteSlice {
start: data.as_mut_ptr_range().start,
length: data.len(),
}
}

View file

@ -1,4 +1,3 @@
#[cfg(feature = "c_api")]
#[repr(C)]
/// Represents a span of memory (`&mut [u8]` ) as a struct usable by C code.
///

View file

@ -0,0 +1,166 @@
use std::ptr::null_mut;
use servicepoint::{
BitVec, ByteGrid, CompressionCode, Origin, Packet, PixelGrid,
};
pub use servicepoint::{Brightness, Command, Offset};
/// Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.
///
/// Returns: pointer to command or NULL
#[no_mangle]
pub unsafe extern "C" fn sp_command_try_from_packet(
packet: *mut Packet,
) -> *mut Command {
let packet = *Box::from_raw(packet);
match Command::try_from(packet) {
Err(_) => null_mut(),
Ok(command) => Box::into_raw(Box::new(command)),
}
}
/// Clones a `Command` instance
#[no_mangle]
pub unsafe extern "C" fn sp_command_clone(
original: *const Command,
) -> *mut Command {
Box::into_raw(Box::new((*original).clone()))
}
/// Allocates a new `Command::Clear` instance
#[no_mangle]
pub unsafe extern "C" fn sp_command_clear() -> *mut Command {
Box::into_raw(Box::new(Command::Clear))
}
/// Allocates a new `Command::HardReset` instance
#[no_mangle]
pub unsafe extern "C" fn sp_command_hard_reset() -> *mut Command {
Box::into_raw(Box::new(Command::HardReset))
}
/// Allocates a new `Command::FadeOut` instance
#[no_mangle]
pub unsafe extern "C" fn sp_command_fade_out() -> *mut Command {
Box::into_raw(Box::new(Command::FadeOut))
}
/// Allocates a new `Command::Brightness` instance
#[no_mangle]
pub unsafe extern "C" fn sp_command_brightness(
brightness: Brightness,
) -> *mut Command {
Box::into_raw(Box::new(Command::Brightness(brightness)))
}
/// Allocates a new `Command::CharBrightness` instance.
/// The passed `ByteGrid` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp_command_char_brightness(
x: usize,
y: usize,
byte_grid: *mut ByteGrid,
) -> *mut Command {
let byte_grid = *Box::from_raw(byte_grid);
Box::into_raw(Box::new(Command::CharBrightness(Origin(x, y), byte_grid)))
}
/// Allocates a new `Command::BitmapLinear` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp_command_bitmap_linear(
offset: Offset,
bit_vec: *mut BitVec,
compression: CompressionCode,
) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinear(
offset,
bit_vec,
compression,
)))
}
/// Allocates a new `Command::BitmapLinearAnd` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp_command_bitmap_linear_and(
offset: Offset,
bit_vec: *mut BitVec,
compression: CompressionCode,
) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinearAnd(
offset,
bit_vec,
compression,
)))
}
/// Allocates a new `Command::BitmapLinearOr` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp_command_bitmap_linear_or(
offset: Offset,
bit_vec: *mut BitVec,
compression: CompressionCode,
) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinearOr(
offset,
bit_vec,
compression,
)))
}
/// Allocates a new `Command::BitmapLinearXor` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
offset: Offset,
bit_vec: *mut BitVec,
compression: CompressionCode,
) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinearXor(
offset,
bit_vec,
compression,
)))
}
/// Allocates a new `Command::Cp437Data` instance.
/// The passed `ByteGrid` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp_command_cp437_data(
x: usize,
y: usize,
byte_grid: *mut ByteGrid,
) -> *mut Command {
let byte_grid = *Box::from_raw(byte_grid);
Box::into_raw(Box::new(Command::Cp437Data(Origin(x, y), byte_grid)))
}
/// Allocates a new `Command::BitmapLinearWin` instance.
/// The passed `PixelGrid` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp_command_bitmap_linear_win(
x: usize,
y: usize,
byte_grid: *mut PixelGrid,
compression_code: CompressionCode,
) -> *mut Command {
let byte_grid = *Box::from_raw(byte_grid);
Box::into_raw(Box::new(Command::BitmapLinearWin(
Origin(x, y),
byte_grid,
compression_code,
)))
}
/// Deallocates a `Command`. Note that connection_send does this implicitly, so you only need
/// to do this if you use the library for parsing commands.
#[no_mangle]
pub unsafe extern "C" fn sp_command_dealloc(ptr: *mut Command) {
_ = Box::from_raw(ptr);
}

View file

@ -0,0 +1,40 @@
use std::ffi::{c_char, CStr};
use std::ptr::null_mut;
pub use servicepoint::Connection;
use servicepoint::Packet;
/// Creates a new instance of Connection.
/// The returned instance has to be deallocated with `connection_dealloc`.
///
/// returns: NULL if connection fails or connected instance
///
/// Panics: bad string encoding
#[no_mangle]
pub unsafe extern "C" fn sp_connection_open(
host: *const c_char,
) -> *mut Connection {
let host = CStr::from_ptr(host).to_str().expect("Bad encoding");
let connection = match Connection::open(host) {
Err(_) => return null_mut(),
Ok(value) => value,
};
Box::into_raw(Box::new(connection))
}
/// Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.
#[no_mangle]
pub unsafe extern "C" fn sp_connection_send(
connection: *const Connection,
command_ptr: *mut Packet,
) -> bool {
let packet = Box::from_raw(command_ptr);
(*connection).send(*packet).is_ok()
}
/// Closes and deallocates a connection instance
#[no_mangle]
pub unsafe extern "C" fn sp_connection_dealloc(ptr: *mut Connection) {
_ = Box::from_raw(ptr);
}

View file

@ -0,0 +1,14 @@
pub use servicepoint::{
CompressionCode, PIXEL_COUNT, PIXEL_HEIGHT, PIXEL_WIDTH, TILE_HEIGHT,
TILE_SIZE, TILE_WIDTH,
};
pub mod bit_vec;
pub mod byte_grid;
pub mod c_slice;
pub mod command;
pub mod connection;
pub mod packet;
pub mod pixel_grid;
pub const FRAME_PACING_MS: u32 = servicepoint::FRAME_PACING.as_millis() as u32;

View file

@ -0,0 +1,37 @@
use std::ptr::null_mut;
use servicepoint::Command;
pub use servicepoint::Packet;
/// Turns a `Command` into a `Packet`. The command gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn sp_packet_from_command(
command: *mut Command,
) -> *mut Packet {
let command = *Box::from_raw(command);
let packet = command.into();
Box::into_raw(Box::new(packet))
}
/// Tries to load a `Packet` from the passed array with the specified length.
///
/// returns: NULL in case of an error, pointer to the allocated packet otherwise
#[no_mangle]
pub unsafe extern "C" fn sp_packet_try_load(
data: *const u8,
length: usize,
) -> *mut Packet {
let data = std::slice::from_raw_parts(data, length);
match Packet::try_from(data) {
Err(_) => null_mut(),
Ok(packet) => Box::into_raw(Box::new(packet)),
}
}
/// Deallocates a `Packet`.
///
/// Note: do not call this if the instance has been consumed in another way, e.g. by sending it.
#[no_mangle]
pub unsafe extern "C" fn sp_packet_dealloc(this: *mut Packet) {
_ = Box::from_raw(this)
}

View file

@ -0,0 +1,102 @@
use servicepoint::{DataRef, Grid, PixelGrid};
use crate::c_slice::CByteSlice;
/// Creates a new `PixelGrid` instance.
/// The returned instance has to be freed with `pixel_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp_pixel_grid_new(
width: usize,
height: usize,
) -> *mut PixelGrid {
Box::into_raw(Box::new(PixelGrid::new(width, height)))
}
/// Loads a `PixelGrid` with the specified dimensions from the provided data.
/// The returned instance has to be freed with `pixel_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp_pixel_grid_load(
width: usize,
height: usize,
data: *const u8,
data_length: usize,
) -> *mut PixelGrid {
let data = std::slice::from_raw_parts(data, data_length);
Box::into_raw(Box::new(PixelGrid::load(width, height, data)))
}
/// Clones a `PixelGrid`.
/// The returned instance has to be freed with `pixel_grid_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp_pixel_grid_clone(
this: *const PixelGrid,
) -> *mut PixelGrid {
Box::into_raw(Box::new((*this).clone()))
}
/// Deallocates a `PixelGrid`.
///
/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
#[no_mangle]
pub unsafe extern "C" fn sp_pixel_grid_dealloc(this: *mut PixelGrid) {
_ = Box::from_raw(this);
}
/// Get the current value at the specified position
#[no_mangle]
pub unsafe extern "C" fn sp_pixel_grid_get(
this: *const PixelGrid,
x: usize,
y: usize,
) -> bool {
(*this).get(x, y)
}
/// Sets the current value at the specified position
#[no_mangle]
pub unsafe extern "C" fn sp_pixel_grid_set(
this: *mut PixelGrid,
x: usize,
y: usize,
value: bool,
) {
(*this).set(x, y, value);
}
/// Fills the whole `PixelGrid` with the specified value
#[no_mangle]
pub unsafe extern "C" fn sp_pixel_grid_fill(this: *mut PixelGrid, value: bool) {
(*this).fill(value);
}
/// Gets the width in pixels of the `PixelGrid` instance.
#[no_mangle]
pub unsafe extern "C" fn sp_pixel_grid_width(this: *const PixelGrid) -> usize {
(*this).width()
}
/// Gets the height in pixels of the `PixelGrid` instance.
#[no_mangle]
pub unsafe extern "C" fn sp_pixel_grid_height(this: *const PixelGrid) -> usize {
(*this).height()
}
/// Gets an unsafe reference to the data of the `PixelGrid` instance.
///
/// ## Safety
///
/// The caller has to make sure to never access the returned memory after the `PixelGrid`
/// instance has been consumed or manually deallocated.
///
/// Reading and writing concurrently to either the original instance or the returned data will
/// result in undefined behavior.
#[no_mangle]
pub unsafe extern "C" fn sp_pixel_grid_unsafe_data_ref(
this: *mut PixelGrid,
) -> CByteSlice {
let data = (*this).data_ref_mut();
CByteSlice {
start: data.as_mut_ptr_range().start,
length: data.len(),
}
}

View file

@ -0,0 +1,17 @@
[package]
name = "servicepoint_binding_cs"
version.workspace = true
edition = "2021"
publish = false
readme = "README.md"
[lib]
crate-type = ["cdylib"]
test = false
[build-dependencies]
csbindgen = "1.8.0"
[dependencies]
servicepoint_binding_c = { version = "0.5.0", path = "../servicepoint_binding_c" }
servicepoint = { version = "0.5.0", path = "../servicepoint" }

View file

@ -0,0 +1,65 @@
# 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 C# bindings for the `servicepoint` library, enabling users to parse, encode and send packets to this display via UDP.
## Examples
```csharp
using ServicePoint;
// using statement calls Dispose() on scope exit, which frees unmanaged instances
using var connection = Connection.Open("127.0.0.1:2342");
using var pixels = PixelGrid.New(Constants.PixelWidth, Constants.PixelHeight);
while (true)
{
pixels.Fill(true);
connection.Send(Command.BitmapLinearWin(0, 0, pixels.Clone()));
Thread.Sleep(5000);
pixels.Fill(false);
connection.Send(Command.BitmapLinearWin(0, 0, pixels.Clone()));
Thread.Sleep(5000);
}
```
A full example including project files 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.
## Installation
NuGet packages are not a good way to distribute native projects ([relevant issue](https://github.com/dotnet/sdk/issues/33845)).
Because of that, there is no NuGet package you can use directly.
Including this repository as a submodule and building from source is the recommended way of using the library.
```bash
git submodule add https://github.com/kaesaecracker/servicepoint.git
git commit -m "add servicepoint submodule"
```
You can now reference `servicepoint-bindings-cs/src/ServicePoint.csproj` in your project.
The rust library will automatically be built.
Please provide more information in the form of an issue if you need the build to copy a different library file for your platform.
## Notes on differences to rust library
Uses C bindings internally to provide a similar API to rust. Things to keep in mind:
- You will get a `NullPointerException` when trying to call a method where the native instance has been consumed already (e.g. when `Send`ing a command instance twice). Send a clone instead of the original if you want to keep using it.
- Some lower-level APIs _will_ panic in native code when used improperly.
Example: manipulating the `Span<byte>` of an object after freeing the instance.
- C# specifics are documented in the library. Use the rust documentation for everything else. Naming and semantics are the same apart from CamelCase instead of kebab_case.
- You will only get rust backtraces in debug builds of the native code.
- F# is not explicitly tested. If there are usability or functionality problems, please open an issue.
- Reading and writing to instances concurrently is not safe. Only reading concurrently is safe.
## Everything else
Look at the main project [README](https://github.com/cccb/servicepoint/blob/main/README.md) for further information.

View file

@ -1,8 +1,8 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint2", "src/ServicePoint2.csproj", "{70EFFA3F-012A-4518-9627-466BEAE4252E}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint", "ServicePoint/ServicePoint.csproj", "{70EFFA3F-012A-4518-9627-466BEAE4252E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lang-cs", "../examples/lang_cs/lang_cs.csproj", "{DA3B8B6E-993A-47DA-844B-F92AF520FF59}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lang-cs", "examples/lang_cs/lang_cs.csproj", "{DA3B8B6E-993A-47DA-844B-F92AF520FF59}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View file

@ -8,222 +8,232 @@ using System;
using System.Runtime.InteropServices;
namespace ServicePoint2.BindGen
namespace ServicePoint.BindGen
{
public static unsafe partial class NativeMethods
{
const string __DllName = "servicepoint2";
const string __DllName = "servicepoint_binding_c";
public const nuint TILE_SIZE = 8;
public const nuint TILE_WIDTH = 56;
public const nuint TILE_HEIGHT = 20;
/// <summary>Creates a new `BitVec` instance. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern BitVec* sp2_bit_vec_new(nuint size);
[DllImport(__DllName, EntryPoint = "sp_bit_vec_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern BitVec* sp_bit_vec_new(nuint size);
/// <summary>Loads a `BitVec` from the provided data. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern BitVec* sp2_bit_vec_load(byte* data, nuint data_length);
[DllImport(__DllName, EntryPoint = "sp_bit_vec_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern BitVec* sp_bit_vec_load(byte* data, nuint data_length);
/// <summary>Clones a `BitVec`. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern BitVec* sp2_bit_vec_clone(BitVec* @this);
[DllImport(__DllName, EntryPoint = "sp_bit_vec_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern BitVec* sp_bit_vec_clone(BitVec* @this);
/// <summary>Deallocates a `BitVec`. Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_bit_vec_dealloc(BitVec* @this);
[DllImport(__DllName, EntryPoint = "sp_bit_vec_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_bit_vec_dealloc(BitVec* @this);
/// <summary>Gets the value of a bit from the `BitVec`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[DllImport(__DllName, EntryPoint = "sp_bit_vec_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool sp2_bit_vec_get(BitVec* @this, nuint index);
public static extern bool sp_bit_vec_get(BitVec* @this, nuint index);
/// <summary>Sets the value of a bit in the `BitVec`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[DllImport(__DllName, EntryPoint = "sp_bit_vec_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool sp2_bit_vec_set(BitVec* @this, nuint index, [MarshalAs(UnmanagedType.U1)] bool value);
public static extern bool sp_bit_vec_set(BitVec* @this, nuint index, [MarshalAs(UnmanagedType.U1)] bool value);
/// <summary>Sets the value of all bits in the `BitVec`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_bit_vec_fill(BitVec* @this, [MarshalAs(UnmanagedType.U1)] bool value);
[DllImport(__DllName, EntryPoint = "sp_bit_vec_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_bit_vec_fill(BitVec* @this, [MarshalAs(UnmanagedType.U1)] bool value);
/// <summary>Gets the length of the `BitVec` in bits.</summary>
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp2_bit_vec_len(BitVec* @this);
[DllImport(__DllName, EntryPoint = "sp_bit_vec_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp_bit_vec_len(BitVec* @this);
/// <summary>Returns true if length is 0.</summary>
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[DllImport(__DllName, EntryPoint = "sp_bit_vec_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool sp2_bit_vec_is_empty(BitVec* @this);
public static extern bool sp_bit_vec_is_empty(BitVec* @this);
/// <summary>Gets an unsafe reference to the data of the `BitVec` instance. ## Safety The caller has to make sure to never access the returned memory after the `BitVec` instance has been consumed or manually deallocated. Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern CByteSlice sp2_bit_vec_unsafe_data_ref(BitVec* @this);
[DllImport(__DllName, EntryPoint = "sp_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern CByteSlice sp_bit_vec_unsafe_data_ref(BitVec* @this);
/// <summary>Creates a new `ByteGrid` instance. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern ByteGrid* sp2_byte_grid_new(nuint width, nuint height);
[DllImport(__DllName, EntryPoint = "sp_byte_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern ByteGrid* sp_byte_grid_new(nuint width, nuint height);
/// <summary>Loads a `ByteGrid` with the specified dimensions from the provided data. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern ByteGrid* sp2_byte_grid_load(nuint width, nuint height, byte* data, nuint data_length);
[DllImport(__DllName, EntryPoint = "sp_byte_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern ByteGrid* sp_byte_grid_load(nuint width, nuint height, byte* data, nuint data_length);
/// <summary>Clones a `ByteGrid`. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern ByteGrid* sp2_byte_grid_clone(ByteGrid* @this);
[DllImport(__DllName, EntryPoint = "sp_byte_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern ByteGrid* sp_byte_grid_clone(ByteGrid* @this);
/// <summary>Deallocates a `ByteGrid`. Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_byte_grid_dealloc(ByteGrid* @this);
[DllImport(__DllName, EntryPoint = "sp_byte_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_byte_grid_dealloc(ByteGrid* @this);
/// <summary>Get the current value at the specified position</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern byte sp2_byte_grid_get(ByteGrid* @this, nuint x, nuint y);
[DllImport(__DllName, EntryPoint = "sp_byte_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern byte sp_byte_grid_get(ByteGrid* @this, nuint x, nuint y);
/// <summary>Sets the current value at the specified position</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_byte_grid_set(ByteGrid* @this, nuint x, nuint y, byte value);
[DllImport(__DllName, EntryPoint = "sp_byte_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_byte_grid_set(ByteGrid* @this, nuint x, nuint y, byte value);
/// <summary>Fills the whole `ByteGrid` with the specified value</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_byte_grid_fill(ByteGrid* @this, byte value);
[DllImport(__DllName, EntryPoint = "sp_byte_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_byte_grid_fill(ByteGrid* @this, byte value);
/// <summary>Gets the width in pixels of the `ByteGrid` instance.</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp2_byte_grid_width(ByteGrid* @this);
[DllImport(__DllName, EntryPoint = "sp_byte_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp_byte_grid_width(ByteGrid* @this);
/// <summary>Gets the height in pixels of the `ByteGrid` instance.</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp2_byte_grid_height(ByteGrid* @this);
[DllImport(__DllName, EntryPoint = "sp_byte_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp_byte_grid_height(ByteGrid* @this);
/// <summary>Gets an unsafe reference to the data of the `ByteGrid` instance. ## Safety The caller has to make sure to never access the returned memory after the `ByteGrid` instance has been consumed or manually deallocated. Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern CByteSlice sp2_byte_grid_unsafe_data_ref(ByteGrid* @this);
[DllImport(__DllName, EntryPoint = "sp_byte_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern CByteSlice sp_byte_grid_unsafe_data_ref(ByteGrid* @this);
/// <summary>Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process. Returns: pointer to command or NULL</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_try_from_packet(Packet* packet);
[DllImport(__DllName, EntryPoint = "sp_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_try_from_packet(Packet* packet);
/// <summary>Clones a `Command` instance</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_clone(Command* original);
[DllImport(__DllName, EntryPoint = "sp_command_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_clone(Command* original);
/// <summary>Allocates a new `Command::Clear` instance</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_clear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_clear();
[DllImport(__DllName, EntryPoint = "sp_command_clear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_clear();
/// <summary>Allocates a new `Command::HardReset` instance</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_hard_reset", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_hard_reset();
[DllImport(__DllName, EntryPoint = "sp_command_hard_reset", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_hard_reset();
/// <summary>Allocates a new `Command::FadeOut` instance</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_fade_out();
[DllImport(__DllName, EntryPoint = "sp_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_fade_out();
/// <summary>Allocates a new `Command::Brightness` instance</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_brightness(byte brightness);
[DllImport(__DllName, EntryPoint = "sp_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_brightness(byte brightness);
/// <summary>Allocates a new `Command::CharBrightness` instance. The passed `ByteGrid` gets deallocated in the process.</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_char_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_char_brightness(nuint x, nuint y, ByteGrid* byte_grid);
[DllImport(__DllName, EntryPoint = "sp_command_char_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_char_brightness(nuint x, nuint y, ByteGrid* byte_grid);
/// <summary>Allocates a new `Command::BitmapLinear` instance. The passed `BitVec` gets deallocated in the process.</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_bitmap_linear(nuint offset, BitVec* bit_vec, CompressionCode compression);
[DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_bitmap_linear(nuint offset, BitVec* bit_vec, CompressionCode compression);
/// <summary>Allocates a new `Command::BitmapLinearAnd` instance. The passed `BitVec` gets deallocated in the process.</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_and", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_bitmap_linear_and(nuint offset, BitVec* bit_vec, CompressionCode compression);
[DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_and", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_bitmap_linear_and(nuint offset, BitVec* bit_vec, CompressionCode compression);
/// <summary>Allocates a new `Command::BitmapLinearOr` instance. The passed `BitVec` gets deallocated in the process.</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_or", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_bitmap_linear_or(nuint offset, BitVec* bit_vec, CompressionCode compression);
[DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_or", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_bitmap_linear_or(nuint offset, BitVec* bit_vec, CompressionCode compression);
/// <summary>Allocates a new `Command::BitmapLinearXor` instance. The passed `BitVec` gets deallocated in the process.</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_xor", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_bitmap_linear_xor(nuint offset, BitVec* bit_vec, CompressionCode compression);
[DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_xor", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_bitmap_linear_xor(nuint offset, BitVec* bit_vec, CompressionCode compression);
/// <summary>Allocates a new `Command::Cp437Data` instance. The passed `ByteGrid` gets deallocated in the process.</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_cp437_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_cp437_data(nuint x, nuint y, ByteGrid* byte_grid);
[DllImport(__DllName, EntryPoint = "sp_command_cp437_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_cp437_data(nuint x, nuint y, ByteGrid* byte_grid);
/// <summary>Allocates a new `Command::BitmapLinearWin` instance. The passed `PixelGrid` gets deallocated in the process.</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_bitmap_linear_win(nuint x, nuint y, PixelGrid* byte_grid, CompressionCode compression_code);
[DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_bitmap_linear_win(nuint x, nuint y, PixelGrid* byte_grid, CompressionCode compression_code);
/// <summary>Deallocates a `Command`. Note that connection_send does this implicitly, so you only need to do this if you use the library for parsing commands.</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_command_dealloc(Command* ptr);
[DllImport(__DllName, EntryPoint = "sp_command_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_command_dealloc(Command* ptr);
/// <summary>Creates a new instance of Connection. The returned instance has to be deallocated with `connection_dealloc`. returns: NULL if connection fails or connected instance Panics: bad string encoding</summary>
[DllImport(__DllName, EntryPoint = "sp2_connection_open", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Connection* sp2_connection_open(byte* host);
[DllImport(__DllName, EntryPoint = "sp_connection_open", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Connection* sp_connection_open(byte* host);
/// <summary>Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.</summary>
[DllImport(__DllName, EntryPoint = "sp2_connection_send", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[DllImport(__DllName, EntryPoint = "sp_connection_send", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool sp2_connection_send(Connection* connection, Packet* command_ptr);
public static extern bool sp_connection_send(Connection* connection, Packet* command_ptr);
/// <summary>Closes and deallocates a connection instance</summary>
[DllImport(__DllName, EntryPoint = "sp2_connection_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_connection_dealloc(Connection* ptr);
[DllImport(__DllName, EntryPoint = "sp_connection_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_connection_dealloc(Connection* ptr);
/// <summary>Creates a new `PixelGrid` instance. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern PixelGrid* sp2_pixel_grid_new(nuint width, nuint height);
[DllImport(__DllName, EntryPoint = "sp_pixel_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern PixelGrid* sp_pixel_grid_new(nuint width, nuint height);
/// <summary>Loads a `PixelGrid` with the specified dimensions from the provided data. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern PixelGrid* sp2_pixel_grid_load(nuint width, nuint height, byte* data, nuint data_length);
[DllImport(__DllName, EntryPoint = "sp_pixel_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern PixelGrid* sp_pixel_grid_load(nuint width, nuint height, byte* data, nuint data_length);
/// <summary>Clones a `PixelGrid`. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern PixelGrid* sp2_pixel_grid_clone(PixelGrid* @this);
[DllImport(__DllName, EntryPoint = "sp_pixel_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern PixelGrid* sp_pixel_grid_clone(PixelGrid* @this);
/// <summary>Deallocates a `PixelGrid`. Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_pixel_grid_dealloc(PixelGrid* @this);
[DllImport(__DllName, EntryPoint = "sp_pixel_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_pixel_grid_dealloc(PixelGrid* @this);
/// <summary>Get the current value at the specified position</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[DllImport(__DllName, EntryPoint = "sp_pixel_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool sp2_pixel_grid_get(PixelGrid* @this, nuint x, nuint y);
public static extern bool sp_pixel_grid_get(PixelGrid* @this, nuint x, nuint y);
/// <summary>Sets the current value at the specified position</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_pixel_grid_set(PixelGrid* @this, nuint x, nuint y, [MarshalAs(UnmanagedType.U1)] bool value);
[DllImport(__DllName, EntryPoint = "sp_pixel_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_pixel_grid_set(PixelGrid* @this, nuint x, nuint y, [MarshalAs(UnmanagedType.U1)] bool value);
/// <summary>Fills the whole `PixelGrid` with the specified value</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_pixel_grid_fill(PixelGrid* @this, [MarshalAs(UnmanagedType.U1)] bool value);
[DllImport(__DllName, EntryPoint = "sp_pixel_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_pixel_grid_fill(PixelGrid* @this, [MarshalAs(UnmanagedType.U1)] bool value);
/// <summary>Gets the width in pixels of the `PixelGrid` instance.</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp2_pixel_grid_width(PixelGrid* @this);
[DllImport(__DllName, EntryPoint = "sp_pixel_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp_pixel_grid_width(PixelGrid* @this);
/// <summary>Gets the height in pixels of the `PixelGrid` instance.</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp2_pixel_grid_height(PixelGrid* @this);
[DllImport(__DllName, EntryPoint = "sp_pixel_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp_pixel_grid_height(PixelGrid* @this);
/// <summary>Gets an unsafe reference to the data of the `PixelGrid` instance. ## Safety The caller has to make sure to never access the returned memory after the `PixelGrid` instance has been consumed or manually deallocated. Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern CByteSlice sp2_pixel_grid_unsafe_data_ref(PixelGrid* @this);
[DllImport(__DllName, EntryPoint = "sp_pixel_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern CByteSlice sp_pixel_grid_unsafe_data_ref(PixelGrid* @this);
/// <summary>Turns a `Command` into a `Packet`. The command gets deallocated in the process.</summary>
[DllImport(__DllName, EntryPoint = "sp2_packet_from_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Packet* sp2_packet_from_command(Command* command);
[DllImport(__DllName, EntryPoint = "sp_packet_from_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Packet* sp_packet_from_command(Command* command);
/// <summary>Tries to load a `Packet` from the passed array with the specified length. returns: NULL in case of an error, pointer to the allocated packet otherwise</summary>
[DllImport(__DllName, EntryPoint = "sp2_packet_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Packet* sp2_packet_try_load(byte* data, nuint length);
[DllImport(__DllName, EntryPoint = "sp_packet_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Packet* sp_packet_try_load(byte* data, nuint length);
/// <summary>Deallocates a `Packet`. Note: do not call this if the instance has been consumed in another way, e.g. by sending it.</summary>
[DllImport(__DllName, EntryPoint = "sp2_packet_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_packet_dealloc(Packet* @this);
[DllImport(__DllName, EntryPoint = "sp_packet_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp_packet_dealloc(Packet* @this);
}
[StructLayout(LayoutKind.Sequential)]
public unsafe partial struct CByteSlice
{
public byte* start;
public nuint length;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe partial struct BitVec
{
@ -244,13 +254,6 @@ namespace ServicePoint2.BindGen
{
}
[StructLayout(LayoutKind.Sequential)]
public unsafe partial struct CByteSlice
{
public byte* start;
public nuint length;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe partial struct Packet
{

View file

@ -1,14 +1,14 @@
using ServicePoint2.BindGen;
using ServicePoint.BindGen;
namespace ServicePoint2;
namespace ServicePoint;
public sealed class BitVec : Sp2NativeInstance<BindGen.BitVec>
public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
{
public static BitVec New(int size)
{
unsafe
{
return new BitVec(NativeMethods.sp2_bit_vec_new((nuint)size));
return new BitVec(NativeMethods.sp_bit_vec_new((nuint)size));
}
}
@ -18,7 +18,7 @@ public sealed class BitVec : Sp2NativeInstance<BindGen.BitVec>
{
fixed (byte* bytesPtr = bytes)
{
return new BitVec(NativeMethods.sp2_bit_vec_load(bytesPtr, (nuint)bytes.Length));
return new BitVec(NativeMethods.sp_bit_vec_load(bytesPtr, (nuint)bytes.Length));
}
}
}
@ -27,7 +27,7 @@ public sealed class BitVec : Sp2NativeInstance<BindGen.BitVec>
{
unsafe
{
return new BitVec(NativeMethods.sp2_bit_vec_clone(Instance));
return new BitVec(NativeMethods.sp_bit_vec_clone(Instance));
}
}
@ -37,14 +37,14 @@ public sealed class BitVec : Sp2NativeInstance<BindGen.BitVec>
{
unsafe
{
return NativeMethods.sp2_bit_vec_get(Instance, (nuint)index);
return NativeMethods.sp_bit_vec_get(Instance, (nuint)index);
}
}
set
{
unsafe
{
NativeMethods.sp2_bit_vec_set(Instance, (nuint)index, value);
NativeMethods.sp_bit_vec_set(Instance, (nuint)index, value);
}
}
}
@ -53,7 +53,7 @@ public sealed class BitVec : Sp2NativeInstance<BindGen.BitVec>
{
unsafe
{
NativeMethods.sp2_bit_vec_fill(Instance, value);
NativeMethods.sp_bit_vec_fill(Instance, value);
}
}
@ -63,7 +63,7 @@ public sealed class BitVec : Sp2NativeInstance<BindGen.BitVec>
{
unsafe
{
return (int)NativeMethods.sp2_bit_vec_len(Instance);
return (int)NativeMethods.sp_bit_vec_len(Instance);
}
}
}
@ -74,7 +74,7 @@ public sealed class BitVec : Sp2NativeInstance<BindGen.BitVec>
{
unsafe
{
var slice = NativeMethods.sp2_bit_vec_unsafe_data_ref(Instance);
var slice = NativeMethods.sp_bit_vec_unsafe_data_ref(Instance);
return new Span<byte>(slice.start, (int)slice.length);
}
}
@ -86,6 +86,6 @@ public sealed class BitVec : Sp2NativeInstance<BindGen.BitVec>
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_bit_vec_dealloc(Instance);
NativeMethods.sp_bit_vec_dealloc(Instance);
}
}

View file

@ -1,15 +1,15 @@
using System.Text;
using ServicePoint2.BindGen;
using ServicePoint.BindGen;
namespace ServicePoint2;
namespace ServicePoint;
public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid>
public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
{
public static ByteGrid New(int width, int height)
{
unsafe
{
return new ByteGrid(NativeMethods.sp2_byte_grid_new((nuint)width, (nuint)height));
return new ByteGrid(NativeMethods.sp_byte_grid_new((nuint)width, (nuint)height));
}
}
@ -19,7 +19,7 @@ public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid>
{
fixed (byte* bytesPtr = bytes)
{
return new ByteGrid(NativeMethods.sp2_byte_grid_load((nuint)width, (nuint)height, bytesPtr,
return new ByteGrid(NativeMethods.sp_byte_grid_load((nuint)width, (nuint)height, bytesPtr,
(nuint)bytes.Length));
}
}
@ -29,7 +29,7 @@ public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid>
{
unsafe
{
return new ByteGrid(NativeMethods.sp2_byte_grid_clone(Instance));
return new ByteGrid(NativeMethods.sp_byte_grid_clone(Instance));
}
}
@ -39,14 +39,14 @@ public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid>
{
unsafe
{
return NativeMethods.sp2_byte_grid_get(Instance, (nuint)x, (nuint)y);
return NativeMethods.sp_byte_grid_get(Instance, (nuint)x, (nuint)y);
}
}
set
{
unsafe
{
NativeMethods.sp2_byte_grid_set(Instance, (nuint)x, (nuint)y, value);
NativeMethods.sp_byte_grid_set(Instance, (nuint)x, (nuint)y, value);
}
}
}
@ -85,7 +85,7 @@ public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid>
{
unsafe
{
NativeMethods.sp2_byte_grid_fill(Instance, value);
NativeMethods.sp_byte_grid_fill(Instance, value);
}
}
@ -95,7 +95,7 @@ public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid>
{
unsafe
{
return (int)NativeMethods.sp2_byte_grid_width(Instance);
return (int)NativeMethods.sp_byte_grid_width(Instance);
}
}
}
@ -106,7 +106,7 @@ public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid>
{
unsafe
{
return (int)NativeMethods.sp2_byte_grid_height(Instance);
return (int)NativeMethods.sp_byte_grid_height(Instance);
}
}
}
@ -117,7 +117,7 @@ public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid>
{
unsafe
{
var slice = NativeMethods.sp2_byte_grid_unsafe_data_ref(Instance);
var slice = NativeMethods.sp_byte_grid_unsafe_data_ref(Instance);
return new Span<byte>(slice.start, (int)slice.length);
}
}
@ -129,6 +129,6 @@ public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid>
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_byte_grid_dealloc(Instance);
NativeMethods.sp_byte_grid_dealloc(Instance);
}
}

View file

@ -1,15 +1,15 @@
using System.Diagnostics.CodeAnalysis;
using ServicePoint2.BindGen;
using ServicePoint.BindGen;
namespace ServicePoint2;
namespace ServicePoint;
public sealed class Command : Sp2NativeInstance<BindGen.Command>
public sealed class Command : SpNativeInstance<BindGen.Command>
{
public static bool TryFromPacket(Packet packet, [MaybeNullWhen(false)] out Command command)
{
unsafe
{
var result = NativeMethods.sp2_command_try_from_packet(packet.Into());
var result = NativeMethods.sp_command_try_from_packet(packet.Into());
if (result == null)
{
command = null;
@ -25,7 +25,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
{
unsafe
{
return new Command(NativeMethods.sp2_command_clone(Instance));
return new Command(NativeMethods.sp_command_clone(Instance));
}
}
@ -33,7 +33,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
{
unsafe
{
return new Command(NativeMethods.sp2_command_clear());
return new Command(NativeMethods.sp_command_clear());
}
}
@ -41,7 +41,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
{
unsafe
{
return new Command(NativeMethods.sp2_command_hard_reset());
return new Command(NativeMethods.sp_command_hard_reset());
}
}
@ -49,7 +49,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
{
unsafe
{
return new Command(NativeMethods.sp2_command_fade_out());
return new Command(NativeMethods.sp_command_fade_out());
}
}
@ -57,7 +57,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
{
unsafe
{
return new Command(NativeMethods.sp2_command_brightness(brightness));
return new Command(NativeMethods.sp_command_brightness(brightness));
}
}
@ -65,7 +65,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
{
unsafe
{
return new Command(NativeMethods.sp2_command_char_brightness((ushort)x, (ushort)y, grid.Into()));
return new Command(NativeMethods.sp_command_char_brightness((ushort)x, (ushort)y, grid.Into()));
}
}
@ -74,7 +74,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
unsafe
{
return new Command(
NativeMethods.sp2_command_bitmap_linear((ushort)offset, bitVec.Into(), compressionCode));
NativeMethods.sp_command_bitmap_linear((ushort)offset, bitVec.Into(), compressionCode));
}
}
@ -83,7 +83,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
unsafe
{
return new Command(
NativeMethods.sp2_command_bitmap_linear_and((ushort)offset, bitVec.Into(), compressionCode));
NativeMethods.sp_command_bitmap_linear_and((ushort)offset, bitVec.Into(), compressionCode));
}
}
@ -92,7 +92,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
unsafe
{
return new Command(
NativeMethods.sp2_command_bitmap_linear_or((ushort)offset, bitVec.Into(), compressionCode));
NativeMethods.sp_command_bitmap_linear_or((ushort)offset, bitVec.Into(), compressionCode));
}
}
@ -101,7 +101,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
unsafe
{
return new Command(
NativeMethods.sp2_command_bitmap_linear_xor((ushort)offset, bitVec.Into(), compressionCode));
NativeMethods.sp_command_bitmap_linear_xor((ushort)offset, bitVec.Into(), compressionCode));
}
}
@ -109,7 +109,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
{
unsafe
{
return new Command(NativeMethods.sp2_command_bitmap_linear_win((ushort)x, (ushort)y, pixelGrid.Into(), compression));
return new Command(NativeMethods.sp_command_bitmap_linear_win((ushort)x, (ushort)y, pixelGrid.Into(), compression));
}
}
@ -117,7 +117,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
{
unsafe
{
return new Command(NativeMethods.sp2_command_cp437_data((ushort)x, (ushort)y, byteGrid.Into()));
return new Command(NativeMethods.sp_command_cp437_data((ushort)x, (ushort)y, byteGrid.Into()));
}
}
@ -127,6 +127,6 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_command_dealloc(Instance);
NativeMethods.sp_command_dealloc(Instance);
}
}

View file

@ -1,9 +1,9 @@
using System.Text;
using ServicePoint2.BindGen;
using ServicePoint.BindGen;
namespace ServicePoint2;
namespace ServicePoint;
public sealed class Connection : Sp2NativeInstance<BindGen.Connection>
public sealed class Connection : SpNativeInstance<BindGen.Connection>
{
public static Connection Open(string host)
{
@ -11,7 +11,7 @@ public sealed class Connection : Sp2NativeInstance<BindGen.Connection>
{
fixed (byte* bytePtr = Encoding.UTF8.GetBytes(host))
{
return new Connection(NativeMethods.sp2_connection_open(bytePtr));
return new Connection(NativeMethods.sp_connection_open(bytePtr));
}
}
}
@ -20,13 +20,13 @@ public sealed class Connection : Sp2NativeInstance<BindGen.Connection>
{
unsafe
{
return NativeMethods.sp2_connection_send(Instance, packet.Into());
return NativeMethods.sp_connection_send(Instance, packet.Into());
}
}
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_connection_dealloc(Instance);
NativeMethods.sp_connection_dealloc(Instance);
}
private unsafe Connection(BindGen.Connection* instance) : base(instance)

View file

@ -1,4 +1,4 @@
namespace ServicePoint2;
namespace ServicePoint;
public static class Constants
{

View file

@ -1,15 +1,15 @@
using System.Diagnostics.CodeAnalysis;
using ServicePoint2.BindGen;
using ServicePoint.BindGen;
namespace ServicePoint2;
namespace ServicePoint;
public sealed class Packet : Sp2NativeInstance<BindGen.Packet>
public sealed class Packet : SpNativeInstance<BindGen.Packet>
{
public static Packet FromCommand(Command command)
{
unsafe
{
return new Packet(NativeMethods.sp2_packet_from_command(command.Into()));
return new Packet(NativeMethods.sp_packet_from_command(command.Into()));
}
}
@ -19,7 +19,7 @@ public sealed class Packet : Sp2NativeInstance<BindGen.Packet>
{
fixed (byte* bytesPtr = bytes)
{
var instance = NativeMethods.sp2_packet_try_load(bytesPtr, (nuint)bytes.Length);
var instance = NativeMethods.sp_packet_try_load(bytesPtr, (nuint)bytes.Length);
packet = instance == null
? null
: new Packet(instance);
@ -34,6 +34,6 @@ public sealed class Packet : Sp2NativeInstance<BindGen.Packet>
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_packet_dealloc(Instance);
NativeMethods.sp_packet_dealloc(Instance);
}
}

View file

@ -1,14 +1,14 @@
using ServicePoint2.BindGen;
using ServicePoint.BindGen;
namespace ServicePoint2;
namespace ServicePoint;
public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
{
public static PixelGrid New(int width, int height)
{
unsafe
{
return new PixelGrid(NativeMethods.sp2_pixel_grid_new((nuint)width, (nuint)height));
return new PixelGrid(NativeMethods.sp_pixel_grid_new((nuint)width, (nuint)height));
}
}
@ -18,7 +18,7 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
{
fixed (byte* bytesPtr = bytes)
{
return new PixelGrid(NativeMethods.sp2_pixel_grid_load((nuint)width, (nuint)height, bytesPtr,
return new PixelGrid(NativeMethods.sp_pixel_grid_load((nuint)width, (nuint)height, bytesPtr,
(nuint)bytes.Length));
}
}
@ -28,7 +28,7 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
{
unsafe
{
return new PixelGrid(NativeMethods.sp2_pixel_grid_clone(Instance));
return new PixelGrid(NativeMethods.sp_pixel_grid_clone(Instance));
}
}
@ -38,14 +38,14 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
{
unsafe
{
return NativeMethods.sp2_pixel_grid_get(Instance, (nuint)x, (nuint)y);
return NativeMethods.sp_pixel_grid_get(Instance, (nuint)x, (nuint)y);
}
}
set
{
unsafe
{
NativeMethods.sp2_pixel_grid_set(Instance, (nuint)x, (nuint)y, value);
NativeMethods.sp_pixel_grid_set(Instance, (nuint)x, (nuint)y, value);
}
}
}
@ -54,7 +54,7 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
{
unsafe
{
NativeMethods.sp2_pixel_grid_fill(Instance, value);
NativeMethods.sp_pixel_grid_fill(Instance, value);
}
}
@ -64,7 +64,7 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
{
unsafe
{
return (int)NativeMethods.sp2_pixel_grid_width(Instance);
return (int)NativeMethods.sp_pixel_grid_width(Instance);
}
}
}
@ -75,7 +75,7 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
{
unsafe
{
return (int)NativeMethods.sp2_pixel_grid_height(Instance);
return (int)NativeMethods.sp_pixel_grid_height(Instance);
}
}
}
@ -86,7 +86,7 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
{
unsafe
{
var slice = NativeMethods.sp2_pixel_grid_unsafe_data_ref(Instance);
var slice = NativeMethods.sp_pixel_grid_unsafe_data_ref(Instance);
return new Span<byte>(slice.start, (int)slice.length);
}
}
@ -98,6 +98,6 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_pixel_grid_dealloc(Instance);
NativeMethods.sp_pixel_grid_dealloc(Instance);
}
}

View file

@ -11,60 +11,54 @@
</PropertyGroup>
<PropertyGroup>
<PackageId>ServicePoint2</PackageId>
<Version>0.3.0</Version>
<PackageId>ServicePoint</PackageId>
<Version>0.5.0</Version>
<Authors>Repository Authors</Authors>
<Company>None</Company>
<Product>ServicePoint2</Product>
<Product>ServicePoint</Product>
<PackageTags>CCCB</PackageTags>
<Description>
C# bindings for the rust crate servicepoint2. You will need a suitable native shared library to use this.
For documentation, see the rust documentation: https://docs.rs/servicepoint2/latest/servicepoint2/.
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>
<Target Name="BuildLibrary" Condition="'$(Configuration)'=='Release'" BeforeTargets="Build">
<Exec Command="cargo build --manifest-path ../../servicepoint2/Cargo.toml --all-features --release"/>
</Target>
<Target Name="BuildLibrary" Condition="'$(Configuration)'=='Debug'" BeforeTargets="Build">
<Exec Command="cargo build --manifest-path ../../servicepoint2/Cargo.toml --all-features"/>
</Target>
<!-- generate C# bindings -->
<Target Name="BuildBindings" Condition="'$(Configuration)'=='Release'" BeforeTargets="Build">
<Exec Command="cargo build --release"/>
</Target>
<Target Name="BuildBindings" Condition="'$(Configuration)'=='Debug'" BeforeTargets="Build">
<Exec Command="cargo build"/>
</Target>
<!-- build native library to include in output -->
<Target Name="BuildLibrary" Condition="'$(Configuration)'=='Release'" BeforeTargets="Build">
<Exec Command="cargo build --manifest-path ../../../crates/servicepoint/Cargo.toml --release"/>
</Target>
<Target Name="BuildLibrary" Condition="'$(Configuration)'=='Debug'" BeforeTargets="Build">
<Exec Command="cargo build --manifest-path ../../../crates/servicepoint/Cargo.toml"/>
</Target>
<!-- include native binary in output -->
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<Content Include="../../target/debug/libservicepoint2.so" CopyToOutputDirectory="Always">
<Link>libservicepoint2.so</Link>
<Content Include="../../../target/debug/libservicepoint_binding_c.so" CopyToOutputDirectory="Always">
<Link>libservicepoint_binding_c.so</Link>
</Content>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Release'">
<Content Include="../../target/release/libservicepoint2.so" CopyToOutputDirectory="Always">
<Link>libservicepoint2.so</Link>
<Content Include="../../../target/release/libservicepoint_binding_c.so" CopyToOutputDirectory="Always">
<Link>libservicepoint_binding_c.so</Link>
</Content>
</ItemGroup>
<ItemGroup>
<!-- include link to source code at revision -->
<None Include="../../README.md" Pack="true" PackagePath="\"/>
<None Include="../README.md" Pack="true" PackagePath="\"/>
<!-- add README.md to package -->
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
</ItemGroup>
<ItemGroup>
<Content Include="..\build.rs">
<Link>build.rs</Link>
</Content>
</ItemGroup>
</Project>

View file

@ -1,8 +1,8 @@
using System.Diagnostics.CodeAnalysis;
namespace ServicePoint2;
namespace ServicePoint;
public static class ServicePoint2Extensions
public static class ServicePointExtensions
{
public static Packet IntoPacket(this Command command)
{

View file

@ -1,6 +1,6 @@
namespace ServicePoint2;
namespace ServicePoint;
public abstract class Sp2NativeInstance<T>
public abstract class SpNativeInstance<T>
: IDisposable
where T : unmanaged
{
@ -16,7 +16,7 @@ public abstract class Sp2NativeInstance<T>
}
}
private protected unsafe Sp2NativeInstance(T* instance)
private protected unsafe SpNativeInstance(T* instance)
{
ArgumentNullException.ThrowIfNull(instance);
_instance = instance;
@ -44,7 +44,7 @@ public abstract class Sp2NativeInstance<T>
GC.SuppressFinalize(this);
}
~Sp2NativeInstance()
~SpNativeInstance()
{
ReleaseUnmanagedResources();
}

View file

@ -0,0 +1,28 @@
fn main() {
println!("cargo:rerun-if-changed=../servicepoint_binding_c/src");
println!("cargo:rerun-if-changed=build.rs");
csbindgen::Builder::default()
.input_extern_file("../servicepoint_binding_c/src/bit_vec.rs")
.input_extern_file("../servicepoint_binding_c/src/byte_grid.rs")
.input_extern_file("../servicepoint_binding_c/src/command.rs")
.input_extern_file("../servicepoint_binding_c/src/connection.rs")
.input_extern_file("../servicepoint_binding_c/src/pixel_grid.rs")
.input_extern_file("../servicepoint_binding_c/src/lib.rs")
.input_extern_file("../servicepoint_binding_c/src/c_slice.rs")
.input_extern_file("../servicepoint_binding_c/src/packet.rs")
.input_extern_file("../servicepoint/src/bit_vec.rs")
.input_extern_file("../servicepoint/src/byte_grid.rs")
.input_extern_file("../servicepoint/src/command.rs")
.input_extern_file("../servicepoint/src/connection.rs")
.input_extern_file("../servicepoint/src/pixel_grid.rs")
.input_extern_file("../servicepoint/src/lib.rs")
.input_extern_file("../servicepoint/src/packet.rs")
.input_extern_file("../servicepoint/src/compression_code.rs")
.csharp_dll_name("servicepoint_binding_c")
.csharp_namespace("ServicePoint.BindGen")
.csharp_use_nint_types(true)
.csharp_class_accessibility("public")
.csharp_generate_const_filter(|_| true)
.generate_csharp_file("ServicePoint/BindGen/ServicePoint.g.cs")
.unwrap();
}

View file

@ -1,5 +1,5 @@
using ServicePoint2;
using CompressionCode = ServicePoint2.BindGen.CompressionCode;
using ServicePoint;
using CompressionCode = ServicePoint.BindGen.CompressionCode;
using var connection = Connection.Open("127.0.0.1:2342");

View file

@ -9,7 +9,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\servicepoint2-binding-cs\src\ServicePoint2.csproj"/>
<ProjectReference Include="../../ServicePoint/ServicePoint.csproj"/>
</ItemGroup>
</Project>

View file

@ -0,0 +1 @@

View file

@ -1,10 +0,0 @@
[package]
name = "announce"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
servicepoint2 = { path = "../../servicepoint2" }
clap = { version = "4.5", features = ["derive"] }
env_logger = "0.11"

View file

@ -1,12 +0,0 @@
[package]
name = "game_of_life"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
servicepoint2 = { path = "../../servicepoint2" }
clap = { version = "4.5", features = ["derive"] }
env_logger = "0.11"
rand = "0.8.5"

View file

@ -1,22 +0,0 @@
ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
OUT_DIR := ${ROOT_DIR}/out
SP2_DIR := ${ROOT_DIR}/../../servicepoint2
SP2_INCLUDE := ${ROOT_DIR}/../../servicepoint2-binding-c
SP2_TARGET_RELEASE := ${SP2_DIR}/target/release
.PHONY: build run clean
all: ${OUT_DIR}/lang_c
run: ${OUT_DIR}/lang_c
out/lang_c
clean:
rm -r ${OUT_DIR} || true
rm -r ${SP2_TARGET_RELEASE} || true
${OUT_DIR}/lang_c: main.c
cd ${SP2_DIR} && cargo build --release --all-features
mkdir -p ${OUT_DIR}
gcc main.c -I ${SP2_INCLUDE} -L ${SP2_TARGET_RELEASE} -Wl,-Bstatic -lservicepoint2 -Wl,-Bdynamic -o ${OUT_DIR}/lang_c

View file

@ -1,19 +0,0 @@
#include <stdio.h>
#include "servicepoint2.h"
int main(void) {
sp2_Connection *connection = sp2_connection_open("localhost:2342");
if (connection == NULL)
return 1;
sp2_PixelGrid *pixels = sp2_pixel_grid_new(sp2_PIXEL_WIDTH, sp2_PIXEL_HEIGHT);
sp2_pixel_grid_fill(pixels, true);
sp2_Command *command = sp2_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
sp2_Packet *packet = sp2_packet_from_command(command);
if (!sp2_connection_send(connection, packet))
return 1;
sp2_connection_dealloc(connection);
return 0;
}

View file

@ -1,10 +0,0 @@
[package]
name = "moving_line"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
servicepoint2 = { path = "../../servicepoint2" }
clap = { version = "4.5", features = ["derive"] }
env_logger = "0.11"

View file

@ -1,12 +0,0 @@
[package]
name = "random_brightness"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
servicepoint2 = { path = "../../servicepoint2" }
clap = { version = "4.5", features = ["derive"] }
env_logger = "0.11"
rand = "0.8"

View file

@ -1,10 +0,0 @@
[package]
name = "wiping_clear"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
servicepoint2 = { path = "../../servicepoint2" }
clap = { version = "4.5", features = ["derive"] }
env_logger = "0.11"

View file

@ -1,4 +0,0 @@
#!/usr/bin/env sh
# if the script crashes here, run `cargo install cbindgen`
cbindgen --config cbindgen.toml --clean --output servicepoint2.h ../servicepoint2

View file

@ -1,264 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "bzip2"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
dependencies = [
"bzip2-sys",
"libc",
]
[[package]]
name = "bzip2-sys"
version = "0.1.11+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "cc"
version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
dependencies = [
"jobserver",
"libc",
"once_cell",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crc32fast"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [
"cfg-if",
]
[[package]]
name = "csbindgen"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf70eb656f35e0e6956cbde31c66431c53d8a546823489719099c71525767a9c"
dependencies = [
"regex",
"syn",
]
[[package]]
name = "flate2"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "jobserver"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
dependencies = [
"libc",
]
[[package]]
name = "libc"
version = "0.2.154"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "lz4"
version = "1.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1"
dependencies = [
"libc",
"lz4-sys",
]
[[package]]
name = "lz4-sys"
version = "1.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "memchr"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "miniz_oxide"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
dependencies = [
"adler",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "pkg-config"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "proc-macro2"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]]
name = "servicepoint-binding-cs"
version = "0.1.0"
dependencies = [
"csbindgen",
"servicepoint2",
]
[[package]]
name = "servicepoint2"
version = "0.2.0"
dependencies = [
"bzip2",
"flate2",
"log",
"lz4",
"zstd",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "zstd"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.10+zstd.1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa"
dependencies = [
"cc",
"pkg-config",
]

View file

@ -1,13 +0,0 @@
[package]
name = "servicepoint-binding-cs"
version = "0.4.2"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
servicepoint2 = { path = "../servicepoint2", features = ["c_api"] }
[build-dependencies]
csbindgen = "1.8.0"

View file

@ -1,19 +0,0 @@
fn main() {
println!("cargo:rerun-if-changed=DOESNOTEXIST"); // rebuild every time
csbindgen::Builder::default()
.input_extern_file("../servicepoint2/src/bit_vec.rs")
.input_extern_file("../servicepoint2/src/byte_grid.rs")
.input_extern_file("../servicepoint2/src/command.rs")
.input_extern_file("../servicepoint2/src/compression_code.rs")
.input_extern_file("../servicepoint2/src/connection.rs")
.input_extern_file("../servicepoint2/src/pixel_grid.rs")
.input_extern_file("../servicepoint2/src/lib.rs")
.input_extern_file("../servicepoint2/src/c_slice.rs")
.input_extern_file("../servicepoint2/src/packet.rs")
.csharp_dll_name("servicepoint2")
.csharp_namespace("ServicePoint2.BindGen")
.csharp_use_nint_types(true)
.csharp_class_accessibility("public")
.generate_csharp_file("src/BindGen/ServicePoint2.g.cs")
.unwrap();
}

167
servicepoint2/Cargo.lock generated
View file

@ -1,167 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "bzip2"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
dependencies = [
"bzip2-sys",
"libc",
]
[[package]]
name = "bzip2-sys"
version = "0.1.11+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "cc"
version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
dependencies = [
"jobserver",
"libc",
"once_cell",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crc32fast"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [
"cfg-if",
]
[[package]]
name = "flate2"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "jobserver"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
dependencies = [
"libc",
]
[[package]]
name = "libc"
version = "0.2.154"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "lz4"
version = "1.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1"
dependencies = [
"libc",
"lz4-sys",
]
[[package]]
name = "lz4-sys"
version = "1.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "miniz_oxide"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
dependencies = [
"adler",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "pkg-config"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "servicepoint2"
version = "0.2.0"
dependencies = [
"bzip2",
"flate2",
"log",
"lz4",
"zstd",
]
[[package]]
name = "zstd"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.10+zstd.1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa"
dependencies = [
"cc",
"pkg-config",
]

View file

@ -1,4 +1,11 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
nativeBuildInputs = with pkgs.buildPackages; [ rustup pkg-config xe lzma cargo-tarpaulin ];
{pkgs ? import <nixpkgs> {}}:
pkgs.mkShell {
nativeBuildInputs = with pkgs.buildPackages; [
rustup
pkg-config
xe
lzma
cargo-tarpaulin
gnumake
];
}