Compare commits

...

9 commits

Author SHA1 Message Date
Vinzenz Schroeter 6dcd26d1c1 use NotNull for parameters
Some checks failed
Rust / build (pull_request) Failing after 1m23s
2025-04-12 13:01:27 +02:00
Vinzenz Schroeter df9c04939d add /*notnull*/ comments in header 2025-04-12 13:01:26 +02:00
Vinzenz Schroeter 992c30b2bc re-export constants from base lib 2025-04-12 13:01:26 +02:00
Vinzenz Schroeter 99c1884ddc wip remove newtypes 2025-04-12 13:01:26 +02:00
Vinzenz Schroeter fed12a4c12 functions for manipulating packets 2025-04-12 13:01:26 +02:00
Vinzenz Schroeter 6f40441dfe wip remove newtypes 2025-04-12 13:01:26 +02:00
Vinzenz Schroeter 8fe4038a43 cargo fmt
All checks were successful
Rust / build (pull_request) Successful in 1m53s
2025-04-11 22:00:01 +02:00
Vinzenz Schroeter 4221ebd406 wip 80k example
All checks were successful
Rust / build (pull_request) Successful in 1m52s
2025-04-11 21:45:22 +02:00
Vinzenz Schroeter 5377f13ea1 wip update to next servicepoint version 2025-04-11 21:40:49 +02:00
20 changed files with 1680 additions and 852 deletions

11
Cargo.lock generated
View file

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "adler2"
@ -98,9 +98,9 @@ dependencies = [
[[package]]
name = "cbindgen"
version = "0.27.0"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb"
checksum = "eadd868a2ce9ca38de7eeafdcec9c7065ef89b42b32f0839278d55f35c54d1ff"
dependencies = [
"clap",
"heck",
@ -407,9 +407,8 @@ dependencies = [
[[package]]
name = "servicepoint"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93b52049be55a15fe37c13249d7f96aa8a5de56e1a41838e74a822ee8316a0c4"
version = "0.13.2"
source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#971bee5065139f220022e8108cfaa9c263b8a8a0"
dependencies = [
"bitvec",
"bzip2",

View file

@ -15,14 +15,31 @@ keywords = ["cccb", "cccb-servicepoint", "cbindgen"]
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
cbindgen = "0.27.0"
cbindgen = "0.28.0"
[dependencies.servicepoint]
version = "0.13.1"
features = ["all_compressions"]
package = "servicepoint"
version = "0.13.2"
default-features = false
features = ["protocol_udp"]
git = "https://git.berlin.ccc.de/servicepoint/servicepoint/"
branch = "next"
[features]
full = ["servicepoint/all_compressions", "servicepoint/default"]
default = ["full"]
[lints.rust]
missing-docs = "warn"
unsafe_op_in_unsafe_fn = "warn"
[package.metadata.docs.rs]
all-features = true
[profile.size-optimized]
inherits = "release"
opt-level = 'z' # Optimize for size
lto = true # Enable link-time optimization
codegen-units = 1 # Reduce number of codegen units to increase optimizations
panic = 'abort' # Abort on panic
strip = true # Strip symbols from binary

View file

@ -6,28 +6,30 @@
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();
cbindgen::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}");
if let Ok(bindings) = cbindgen::generate_with_config(crate_dir, config) {
bindings.write_to_file(&header_file);
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}");
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}");
}
} else {
eprintln!("cargo:warning=Servicepoint header could not be generated");
}
}

View file

@ -19,18 +19,26 @@ line_endings = "LF"
style = "type"
usize_is_size_t = true
# this is needed because otherwise the order in the C# bindings is different on different machines
# this is needed because otherwise the order in the C bindings is different on different machines
sort_by = "Name"
[parse]
parse_deps = false
parse_deps = true
include = ["servicepoint"]
extra_bindings = ["servicepoint"]
[parse.expand]
all_features = true
features = ["full"]
[export]
include = []
exclude = []
[export.rename]
"TypedCommand" = "Command"
[enum]
rename_variants = "QualifiedScreamingSnakeCase"
[ptr]
non_null_attribute = "/*notnull*/"

695
examples/lang_c/Cargo.lock generated Normal file
View file

@ -0,0 +1,695 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "adler2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "anstream"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
dependencies = [
"anstyle",
"once_cell",
"windows-sys",
]
[[package]]
name = "bitflags"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "bzip2"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
dependencies = [
"bzip2-sys",
]
[[package]]
name = "bzip2-sys"
version = "0.1.13+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
dependencies = [
"cc",
"pkg-config",
]
[[package]]
name = "cbindgen"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eadd868a2ce9ca38de7eeafdcec9c7065ef89b42b32f0839278d55f35c54d1ff"
dependencies = [
"clap",
"heck",
"indexmap",
"log",
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn",
"tempfile",
"toml",
]
[[package]]
name = "cc"
version = "1.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
dependencies = [
"jobserver",
"libc",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.5.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_lex"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "crc32fast"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "flate2"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "getrandom"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "indexmap"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jobserver"
version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
dependencies = [
"getrandom",
"libc",
]
[[package]]
name = "lang_c"
version = "0.1.0"
dependencies = [
"cc",
"servicepoint_binding_c",
]
[[package]]
name = "libc"
version = "0.2.171"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "miniz_oxide"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"adler2",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "pkg-config"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "rust-lzma"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d62915608f6cee1d7f2fc00f28b4f058ff79d6e4ec3c2fe0006b09b52437c84"
dependencies = [
"pkg-config",
"vcpkg",
]
[[package]]
name = "rustix"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
dependencies = [
"serde",
]
[[package]]
name = "servicepoint"
version = "0.13.2"
source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#971bee5065139f220022e8108cfaa9c263b8a8a0"
dependencies = [
"bitvec",
"bzip2",
"flate2",
"log",
"once_cell",
"rust-lzma",
"thiserror",
"zstd",
]
[[package]]
name = "servicepoint_binding_c"
version = "0.13.1"
dependencies = [
"cbindgen",
"servicepoint",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tempfile"
version = "3.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
dependencies = [
"fastrand",
"getrandom",
"once_cell",
"rustix",
"windows-sys",
]
[[package]]
name = "thiserror"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "toml"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "wasi"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
dependencies = [
"memchr",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags",
]
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]]
name = "zstd"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.15+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
dependencies = [
"cc",
"pkg-config",
]

View file

@ -1,7 +1,47 @@
CC := gcc
CARGO := rustup run nightly cargo
THIS_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
REPO_ROOT := $(THIS_DIR)/../../
RUST_TARGET_DIR := $(REPO_ROOT)/target/x86_64-unknown-linux-musl/size-optimized
RUSTFLAGS := -Zlocation-detail=none \
-Zfmt-debug=none \
-C linker=musl-gcc \
-C link-arg=-s \
-C link-arg=--gc-sections \
-C link-arg=-z,norelro \
-C link-arg=--hash-style=gnu \
--crate-type=staticlib \
-C panic=abort
CARGOFLAGS := --manifest-path=$(REPO_ROOT)/Cargo.toml \
--profile=size-optimized \
--no-default-features \
--target=x86_64-unknown-linux-musl \
-Zbuild-std="core,std,alloc,proc_macro,panic_abort" \
-Zbuild-std-features="panic_immediate_abort" \
CCFLAGS := -static -Os \
-ffunction-sections -fdata-sections \
-fwrapv -fomit-frame-pointer -fno-stack-protector\
-fwhole-program \
-nodefaultlibs -lservicepoint_binding_c -lc \
-Wl,--gc-sections \
-fno-unroll-loops \
-fno-unwind-tables -fno-asynchronous-unwind-tables \
-fmerge-all-constants \
-Wl,-z,norelro \
-Wl,--hash-style=gnu \
-fvisibility=hidden \
-Bsymbolic \
-Wl,--exclude-libs,ALL \
-fno-ident
#-fuse-ld=gold \
-fno-exceptions
#-Wl,--icf=all \
export SERVICEPOINT_HEADER_OUT := $(THIS_DIR)/include
build: out/lang_c
@ -15,20 +55,19 @@ run: out/lang_c
PHONY: build clean dependencies run
out/lang_c: dependencies src/main.c
out/lang_c_unstripped: 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
-I $(SERVICEPOINT_HEADER_OUT) \
-L $(RUST_TARGET_DIR)\
$(CCFLAGS) \
-o out/lang_c_unstripped
out/lang_c: out/lang_c_unstripped
strip -s -R .comment -R .gnu.version --strip-unneeded out/lang_c_unstripped -o out/lang_c
#strip -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag
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)/Cargo.toml \
--release
${CARGO} rustc $(CARGOFLAGS) -- $(RUSTFLAGS)
FORCE: ;

File diff suppressed because it is too large Load diff

View file

@ -2,15 +2,26 @@
#include "servicepoint.h"
int main(void) {
SPConnection *connection = sp_connection_open("localhost:2342");
UdpConnection *connection = sp_connection_open("localhost:2342");
if (connection == NULL)
return 1;
SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
Bitmap *pixels = sp_bitmap_new(PIXEL_WIDTH, PIXEL_HEIGHT);
if (pixels == NULL)
return 1;
sp_bitmap_fill(pixels, true);
SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, SP_COMPRESSION_CODE_UNCOMPRESSED);
sp_connection_send_command(connection, command);
Command *command = sp_command_bitmap_linear_win(0, 0, pixels, COMPRESSION_CODE_UNCOMPRESSED);
if (command == NULL)
return 1;
Packet *packet = sp_packet_from_command(command);
Header *header = sp_packet_get_header(packet);
printf("[%d, %d, %d, %d, %d]\n", header->command_code, header->a, header->b, header->c, header->d);
sp_connection_send_packet(connection, packet);
sp_connection_free(connection);
return 0;

View file

@ -33,25 +33,35 @@
{ pkgs, system }:
{
default = pkgs.mkShell rec {
packages = with pkgs; [
buildInputs = with pkgs;[
xe
xz
libgcc
#glibc.static
musl
libunwind
];
nativeBuildInputs = with pkgs;[
(pkgs.symlinkJoin {
name = "rust-toolchain";
paths = with pkgs; [
rustc
cargo
rustPlatform.rustcSrc
rustfmt
clippy
#rustc
#cargo
#rustPlatform.rustcSrc
#rustfmt
#clippy
cargo-expand
cargo-tarpaulin
rustup
];
})
gcc
gnumake
xe
xz
pkg-config
];
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
};
}

View file

@ -1,24 +1,23 @@
//! C functions for interacting with [SPBitmap]s
//!
//! prefix `sp_bitmap_`
//!
//! A grid of pixels.
//!
//! # Examples
//!
//! ```C
//! Cp437Grid grid = sp_bitmap_new(8, 3);
//! sp_bitmap_fill(grid, true);
//! sp_bitmap_set(grid, 0, 0, false);
//! sp_bitmap_free(grid);
//! ```
use servicepoint::{DataRef, Grid};
use servicepoint::{Bitmap, DataRef, Grid};
use std::ptr::NonNull;
use crate::byte_slice::SPByteSlice;
/// A grid of pixels.
///
/// # Examples
///
/// ```C
/// Cp437Grid grid = sp_bitmap_new(8, 3);
/// sp_bitmap_fill(grid, true);
/// sp_bitmap_set(grid, 0, 0, false);
/// sp_bitmap_free(grid);
/// ```
pub struct SPBitmap(pub(crate) servicepoint::Bitmap);
/// Creates a new [SPBitmap] with the specified dimensions.
///
/// # Arguments
@ -26,9 +25,11 @@ pub struct SPBitmap(pub(crate) servicepoint::Bitmap);
/// - `width`: size in pixels in x-direction
/// - `height`: size in pixels in y-direction
///
/// returns: [SPBitmap] initialized to all pixels off. Will never return NULL.
/// returns: [SPBitmap] initialized to all pixels off, or NULL in case of an error.
///
/// # Panics
/// # Errors
///
/// In the following cases, this function will return NULL:
///
/// - when the width is not dividable by 8
///
@ -42,9 +43,12 @@ pub struct SPBitmap(pub(crate) servicepoint::Bitmap);
pub unsafe extern "C" fn sp_bitmap_new(
width: usize,
height: usize,
) -> NonNull<SPBitmap> {
let result = Box::new(SPBitmap(servicepoint::Bitmap::new(width, height)));
NonNull::from(Box::leak(result))
) -> *mut Bitmap {
if let Some(bitmap) = Bitmap::new(width, height) {
Box::leak(Box::new(bitmap))
} else {
std::ptr::null_mut()
}
}
/// Creates a new [SPBitmap] with a size matching the screen.
@ -58,8 +62,8 @@ pub unsafe extern "C" fn sp_bitmap_new(
/// - the returned instance is freed in some way, either by using a consuming function or
/// by explicitly calling [sp_bitmap_free].
#[no_mangle]
pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull<SPBitmap> {
let result = Box::new(SPBitmap(servicepoint::Bitmap::max_sized()));
pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull<Bitmap> {
let result = Box::new(Bitmap::max_sized());
NonNull::from(Box::leak(result))
}
@ -70,13 +74,18 @@ pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull<SPBitmap> {
/// - `width`: size in pixels in x-direction
/// - `height`: size in pixels in y-direction
///
/// returns: [SPBitmap] that contains a copy of the provided data. Will never return NULL.
/// returns: [SPBitmap] that contains a copy of the provided data, or NULL in case of an error.
///
/// # Errors
///
/// In the following cases, this function will return NULL:
///
/// - when the dimensions and data size do not match exactly.
/// - when the width is not dividable by 8
///
/// # Panics
///
/// - when `data` is NULL
/// - when the dimensions and data size do not match exactly.
/// - when the width is not dividable by 8
///
/// # Safety
///
@ -89,14 +98,14 @@ pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull<SPBitmap> {
pub unsafe extern "C" fn sp_bitmap_load(
width: usize,
height: usize,
data: *const u8,
data_length: usize,
) -> NonNull<SPBitmap> {
assert!(!data.is_null());
let data = std::slice::from_raw_parts(data, data_length);
let result =
Box::new(SPBitmap(servicepoint::Bitmap::load(width, height, data)));
NonNull::from(Box::leak(result))
data: SPByteSlice,
) -> *mut Bitmap {
let data = unsafe { data.as_slice() };
if let Ok(bitmap) = Bitmap::load(width, height, data) {
Box::leak(Box::new(bitmap))
} else {
std::ptr::null_mut()
}
}
/// Clones a [SPBitmap].
@ -117,10 +126,9 @@ pub unsafe extern "C" fn sp_bitmap_load(
/// by explicitly calling `sp_bitmap_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_bitmap_clone(
bitmap: *const SPBitmap,
) -> NonNull<SPBitmap> {
assert!(!bitmap.is_null());
let result = Box::new(SPBitmap((*bitmap).0.clone()));
bitmap: NonNull<Bitmap>,
) -> NonNull<Bitmap> {
let result = Box::new(unsafe { bitmap.as_ref().clone() });
NonNull::from(Box::leak(result))
}
@ -135,14 +143,11 @@ pub unsafe extern "C" fn sp_bitmap_clone(
/// The caller has to make sure that:
///
/// - `bitmap` points to a valid [SPBitmap]
/// - `bitmap` is not used concurrently or after bitmap call
/// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand]
///
/// [SPCommand]: [crate::SPCommand]
#[no_mangle]
pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) {
assert!(!bitmap.is_null());
_ = Box::from_raw(bitmap);
pub unsafe extern "C" fn sp_bitmap_free(bitmap: NonNull<Bitmap>) {
_ = unsafe { Box::from_raw(bitmap.as_ptr()) };
}
/// Gets the current value at the specified position in the [SPBitmap].
@ -165,12 +170,11 @@ pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) {
/// - `bitmap` is not written to concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_bitmap_get(
bitmap: *const SPBitmap,
bitmap: NonNull<Bitmap>,
x: usize,
y: usize,
) -> bool {
assert!(!bitmap.is_null());
(*bitmap).0.get(x, y)
unsafe { bitmap.as_ref().get(x, y) }
}
/// Sets the value of the specified position in the [SPBitmap].
@ -196,13 +200,12 @@ pub unsafe extern "C" fn sp_bitmap_get(
/// - `bitmap` is not written to or read from concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_bitmap_set(
bitmap: *mut SPBitmap,
bitmap: NonNull<Bitmap>,
x: usize,
y: usize,
value: bool,
) {
assert!(!bitmap.is_null());
(*bitmap).0.set(x, y, value);
unsafe { (*bitmap.as_ptr()).set(x, y, value) };
}
/// Sets the state of all pixels in the [SPBitmap].
@ -223,9 +226,8 @@ pub unsafe extern "C" fn sp_bitmap_set(
/// - `bitmap` points to a valid [SPBitmap]
/// - `bitmap` is not written to or read from concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_bitmap_fill(bitmap: *mut SPBitmap, value: bool) {
assert!(!bitmap.is_null());
(*bitmap).0.fill(value);
pub unsafe extern "C" fn sp_bitmap_fill(bitmap: NonNull<Bitmap>, value: bool) {
unsafe { (*bitmap.as_ptr()).fill(value) };
}
/// Gets the width in pixels of the [SPBitmap] instance.
@ -244,9 +246,8 @@ pub unsafe extern "C" fn sp_bitmap_fill(bitmap: *mut SPBitmap, value: bool) {
///
/// - `bitmap` points to a valid [SPBitmap]
#[no_mangle]
pub unsafe extern "C" fn sp_bitmap_width(bitmap: *const SPBitmap) -> usize {
assert!(!bitmap.is_null());
(*bitmap).0.width()
pub unsafe extern "C" fn sp_bitmap_width(bitmap: NonNull<Bitmap>) -> usize {
unsafe { bitmap.as_ref().width() }
}
/// Gets the height in pixels of the [SPBitmap] instance.
@ -265,9 +266,8 @@ pub unsafe extern "C" fn sp_bitmap_width(bitmap: *const SPBitmap) -> usize {
///
/// - `bitmap` points to a valid [SPBitmap]
#[no_mangle]
pub unsafe extern "C" fn sp_bitmap_height(bitmap: *const SPBitmap) -> usize {
assert!(!bitmap.is_null());
(*bitmap).0.height()
pub unsafe extern "C" fn sp_bitmap_height(bitmap: NonNull<Bitmap>) -> usize {
unsafe { bitmap.as_ref().height() }
}
/// Gets an unsafe reference to the data of the [SPBitmap] instance.
@ -285,12 +285,7 @@ pub unsafe extern "C" fn sp_bitmap_height(bitmap: *const SPBitmap) -> usize {
/// - the returned memory range is never accessed concurrently, either via the [SPBitmap] or directly
#[no_mangle]
pub unsafe extern "C" fn sp_bitmap_unsafe_data_ref(
bitmap: *mut SPBitmap,
mut bitmap: NonNull<Bitmap>,
) -> SPByteSlice {
assert!(!bitmap.is_null());
let data = (*bitmap).0.data_ref_mut();
SPByteSlice {
start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
length: data.len(),
}
unsafe { SPByteSlice::from_slice(bitmap.as_mut().data_ref_mut()) }
}

View file

@ -13,19 +13,7 @@ use std::ptr::NonNull;
/// sp_bitvec_set(vec, 5, true);
/// sp_bitvec_free(vec);
/// ```
pub struct SPBitVec(servicepoint::BitVec);
impl From<servicepoint::BitVec> for SPBitVec {
fn from(actual: servicepoint::BitVec) -> Self {
Self(actual)
}
}
impl From<SPBitVec> for servicepoint::BitVec {
fn from(value: SPBitVec) -> Self {
value.0
}
}
pub struct SPBitVec(pub(crate) servicepoint::BitVecU8Msb0);
impl Clone for SPBitVec {
fn clone(&self) -> Self {
@ -53,7 +41,8 @@ impl Clone for SPBitVec {
/// by explicitly calling `sp_bitvec_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_bitvec_new(size: usize) -> NonNull<SPBitVec> {
let result = Box::new(SPBitVec(servicepoint::BitVec::repeat(false, size)));
let result =
Box::new(SPBitVec(servicepoint::BitVecU8Msb0::repeat(false, size)));
NonNull::from(Box::leak(result))
}
@ -75,12 +64,11 @@ pub unsafe extern "C" fn sp_bitvec_new(size: usize) -> NonNull<SPBitVec> {
/// by explicitly calling `sp_bitvec_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_bitvec_load(
data: *const u8,
data_length: usize,
data: SPByteSlice,
) -> NonNull<SPBitVec> {
assert!(!data.is_null());
let data = std::slice::from_raw_parts(data, data_length);
let result = Box::new(SPBitVec(servicepoint::BitVec::from_slice(data)));
let data = unsafe { data.as_slice() };
let result =
Box::new(SPBitVec(servicepoint::BitVecU8Msb0::from_slice(data)));
NonNull::from(Box::leak(result))
}
@ -102,10 +90,9 @@ pub unsafe extern "C" fn sp_bitvec_load(
/// by explicitly calling `sp_bitvec_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_bitvec_clone(
bit_vec: *const SPBitVec,
bit_vec: NonNull<SPBitVec>,
) -> NonNull<SPBitVec> {
assert!(!bit_vec.is_null());
let result = Box::new((*bit_vec).clone());
let result = Box::new(unsafe { bit_vec.as_ref().clone() });
NonNull::from(Box::leak(result))
}
@ -125,9 +112,8 @@ pub unsafe extern "C" fn sp_bitvec_clone(
///
/// [SPCommand]: [crate::SPCommand]
#[no_mangle]
pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) {
assert!(!bit_vec.is_null());
_ = Box::from_raw(bit_vec);
pub unsafe extern "C" fn sp_bitvec_free(bit_vec: NonNull<SPBitVec>) {
_ = unsafe { Box::from_raw(bit_vec.as_ptr()) };
}
/// Gets the value of a bit from the [SPBitVec].
@ -152,11 +138,10 @@ pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) {
/// - `bit_vec` is not written to concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_bitvec_get(
bit_vec: *const SPBitVec,
bit_vec: NonNull<SPBitVec>,
index: usize,
) -> bool {
assert!(!bit_vec.is_null());
*(*bit_vec).0.get(index).unwrap()
unsafe { *bit_vec.as_ref().0.get(index).unwrap() }
}
/// Sets the value of a bit in the [SPBitVec].
@ -180,12 +165,11 @@ pub unsafe extern "C" fn sp_bitvec_get(
/// - `bit_vec` is not written to or read from concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_bitvec_set(
bit_vec: *mut SPBitVec,
bit_vec: NonNull<SPBitVec>,
index: usize,
value: bool,
) {
assert!(!bit_vec.is_null());
(*bit_vec).0.set(index, value)
unsafe { (*bit_vec.as_ptr()).0.set(index, value) }
}
/// Sets the value of all bits in the [SPBitVec].
@ -206,9 +190,11 @@ pub unsafe extern "C" fn sp_bitvec_set(
/// - `bit_vec` points to a valid [SPBitVec]
/// - `bit_vec` is not written to or read from concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_bitvec_fill(bit_vec: *mut SPBitVec, value: bool) {
assert!(!bit_vec.is_null());
(*bit_vec).0.fill(value)
pub unsafe extern "C" fn sp_bitvec_fill(
bit_vec: NonNull<SPBitVec>,
value: bool,
) {
unsafe { (*bit_vec.as_ptr()).0.fill(value) }
}
/// Gets the length of the [SPBitVec] in bits.
@ -227,9 +213,8 @@ pub unsafe extern "C" fn sp_bitvec_fill(bit_vec: *mut SPBitVec, value: bool) {
///
/// - `bit_vec` points to a valid [SPBitVec]
#[no_mangle]
pub unsafe extern "C" fn sp_bitvec_len(bit_vec: *const SPBitVec) -> usize {
assert!(!bit_vec.is_null());
(*bit_vec).0.len()
pub unsafe extern "C" fn sp_bitvec_len(bit_vec: NonNull<SPBitVec>) -> usize {
unsafe { bit_vec.as_ref().0.len() }
}
/// Returns true if length is 0.
@ -248,9 +233,10 @@ pub unsafe extern "C" fn sp_bitvec_len(bit_vec: *const SPBitVec) -> usize {
///
/// - `bit_vec` points to a valid [SPBitVec]
#[no_mangle]
pub unsafe extern "C" fn sp_bitvec_is_empty(bit_vec: *const SPBitVec) -> bool {
assert!(!bit_vec.is_null());
(*bit_vec).0.is_empty()
pub unsafe extern "C" fn sp_bitvec_is_empty(
bit_vec: NonNull<SPBitVec>,
) -> bool {
unsafe { bit_vec.as_ref().0.is_empty() }
}
/// Gets an unsafe reference to the data of the [SPBitVec] instance.
@ -272,12 +258,7 @@ pub unsafe extern "C" fn sp_bitvec_is_empty(bit_vec: *const SPBitVec) -> bool {
/// - the returned memory range is never accessed concurrently, either via the [SPBitVec] or directly
#[no_mangle]
pub unsafe extern "C" fn sp_bitvec_unsafe_data_ref(
bit_vec: *mut SPBitVec,
bit_vec: NonNull<SPBitVec>,
) -> SPByteSlice {
assert!(!bit_vec.is_null());
let data = (*bit_vec).0.as_raw_mut_slice();
SPByteSlice {
start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
length: data.len(),
}
unsafe { SPByteSlice::from_slice((*bit_vec.as_ptr()).0.as_raw_mut_slice()) }
}

View file

@ -1,11 +1,28 @@
//! C functions for interacting with [SPBrightnessGrid]s
//!
//! prefix `sp_brightness_grid_`
//!
//!
//! A grid containing brightness values.
//!
//! # Examples
//! ```C
//! SPConnection connection = sp_connection_open("127.0.0.1:2342");
//! if (connection == NULL)
//! return 1;
//!
//! SPBrightnessGrid grid = sp_brightness_grid_new(2, 2);
//! sp_brightness_grid_set(grid, 0, 0, 0);
//! sp_brightness_grid_set(grid, 1, 1, 10);
//!
//! SPCommand command = sp_command_char_brightness(grid);
//! sp_connection_free(connection);
//! ```
use crate::SPByteSlice;
use servicepoint::{DataRef, Grid};
use servicepoint::{BrightnessGrid, DataRef, Grid};
use std::convert::Into;
use std::intrinsics::transmute;
use std::mem::transmute;
use std::ptr::NonNull;
/// see [servicepoint::Brightness::MIN]
@ -15,24 +32,6 @@ pub const SP_BRIGHTNESS_MAX: u8 = 11;
/// Count of possible brightness values
pub const SP_BRIGHTNESS_LEVELS: u8 = 12;
/// A grid containing brightness values.
///
/// # Examples
/// ```C
/// SPConnection connection = sp_connection_open("127.0.0.1:2342");
/// if (connection == NULL)
/// return 1;
///
/// SPBrightnessGrid grid = sp_brightness_grid_new(2, 2);
/// sp_brightness_grid_set(grid, 0, 0, 0);
/// sp_brightness_grid_set(grid, 1, 1, 10);
///
/// SPCommand command = sp_command_char_brightness(grid);
/// sp_connection_free(connection);
/// ```
#[derive(Clone)]
pub struct SPBrightnessGrid(pub(crate) servicepoint::BrightnessGrid);
/// Creates a new [SPBrightnessGrid] with the specified dimensions.
///
/// returns: [SPBrightnessGrid] initialized to 0. Will never return NULL.
@ -47,10 +46,8 @@ pub struct SPBrightnessGrid(pub(crate) servicepoint::BrightnessGrid);
pub unsafe extern "C" fn sp_brightness_grid_new(
width: usize,
height: usize,
) -> NonNull<SPBrightnessGrid> {
let result = Box::new(SPBrightnessGrid(servicepoint::BrightnessGrid::new(
width, height,
)));
) -> NonNull<BrightnessGrid> {
let result = Box::new(BrightnessGrid::new(width, height));
NonNull::from(Box::leak(result))
}
@ -75,16 +72,18 @@ pub unsafe extern "C" fn sp_brightness_grid_new(
pub unsafe extern "C" fn sp_brightness_grid_load(
width: usize,
height: usize,
data: *const u8,
data_length: usize,
) -> NonNull<SPBrightnessGrid> {
assert!(!data.is_null());
let data = std::slice::from_raw_parts(data, data_length);
let grid = servicepoint::ByteGrid::load(width, height, data);
let grid = servicepoint::BrightnessGrid::try_from(grid)
.expect("invalid brightness value");
let result = Box::new(SPBrightnessGrid(grid));
NonNull::from(Box::leak(result))
data: SPByteSlice,
) -> *mut BrightnessGrid {
let data = unsafe { data.as_slice() };
let grid = match servicepoint::ByteGrid::load(width, height, data) {
None => return std::ptr::null_mut(),
Some(grid) => grid,
};
if let Ok(grid) = BrightnessGrid::try_from(grid) {
Box::leak(Box::new(grid))
} else {
std::ptr::null_mut()
}
}
/// Clones a [SPBrightnessGrid].
@ -109,10 +108,9 @@ pub unsafe extern "C" fn sp_brightness_grid_load(
/// by explicitly calling `sp_brightness_grid_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_clone(
brightness_grid: *const SPBrightnessGrid,
) -> NonNull<SPBrightnessGrid> {
assert!(!brightness_grid.is_null());
let result = Box::new((*brightness_grid).clone());
brightness_grid: NonNull<BrightnessGrid>,
) -> NonNull<BrightnessGrid> {
let result = Box::new(unsafe { brightness_grid.as_ref().clone() });
NonNull::from(Box::leak(result))
}
@ -137,10 +135,9 @@ pub unsafe extern "C" fn sp_brightness_grid_clone(
/// [SPCommand]: [crate::SPCommand]
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_free(
brightness_grid: *mut SPBrightnessGrid,
brightness_grid: NonNull<BrightnessGrid>,
) {
assert!(!brightness_grid.is_null());
_ = Box::from_raw(brightness_grid);
_ = unsafe { Box::from_raw(brightness_grid.as_ptr()) };
}
/// Gets the current value at the specified position.
@ -165,12 +162,11 @@ pub unsafe extern "C" fn sp_brightness_grid_free(
/// - `brightness_grid` is not written to concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_get(
brightness_grid: *const SPBrightnessGrid,
brightness_grid: NonNull<BrightnessGrid>,
x: usize,
y: usize,
) -> u8 {
assert!(!brightness_grid.is_null());
(*brightness_grid).0.get(x, y).into()
unsafe { brightness_grid.as_ref().get(x, y) }.into()
}
/// Sets the value of the specified position in the [SPBrightnessGrid].
@ -197,15 +193,14 @@ pub unsafe extern "C" fn sp_brightness_grid_get(
/// - `brightness_grid` is not written to or read from concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_set(
brightness_grid: *mut SPBrightnessGrid,
brightness_grid: NonNull<BrightnessGrid>,
x: usize,
y: usize,
value: u8,
) {
assert!(!brightness_grid.is_null());
let brightness = servicepoint::Brightness::try_from(value)
.expect("invalid brightness value");
(*brightness_grid).0.set(x, y, brightness);
unsafe { (*brightness_grid.as_ptr()).set(x, y, brightness) };
}
/// Sets the value of all cells in the [SPBrightnessGrid].
@ -228,13 +223,12 @@ pub unsafe extern "C" fn sp_brightness_grid_set(
/// - `brightness_grid` is not written to or read from concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_fill(
brightness_grid: *mut SPBrightnessGrid,
brightness_grid: NonNull<BrightnessGrid>,
value: u8,
) {
assert!(!brightness_grid.is_null());
let brightness = servicepoint::Brightness::try_from(value)
.expect("invalid brightness value");
(*brightness_grid).0.fill(brightness);
unsafe { (*brightness_grid.as_ptr()).fill(brightness) };
}
/// Gets the width of the [SPBrightnessGrid] instance.
@ -256,10 +250,9 @@ pub unsafe extern "C" fn sp_brightness_grid_fill(
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_width(
brightness_grid: *const SPBrightnessGrid,
brightness_grid: NonNull<BrightnessGrid>,
) -> usize {
assert!(!brightness_grid.is_null());
(*brightness_grid).0.width()
unsafe { brightness_grid.as_ref().width() }
}
/// Gets the height of the [SPBrightnessGrid] instance.
@ -281,10 +274,9 @@ pub unsafe extern "C" fn sp_brightness_grid_width(
/// - `brightness_grid` points to a valid [SPBrightnessGrid]
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_height(
brightness_grid: *const SPBrightnessGrid,
brightness_grid: NonNull<BrightnessGrid>,
) -> usize {
assert!(!brightness_grid.is_null());
(*brightness_grid).0.height()
unsafe { brightness_grid.as_ref().height() }
}
/// Gets an unsafe reference to the data of the [SPBrightnessGrid] instance.
@ -308,15 +300,10 @@ pub unsafe extern "C" fn sp_brightness_grid_height(
/// - the returned memory range is never accessed concurrently, either via the [SPBrightnessGrid] or directly
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref(
brightness_grid: *mut SPBrightnessGrid,
brightness_grid: NonNull<BrightnessGrid>,
) -> SPByteSlice {
assert!(!brightness_grid.is_null());
assert_eq!(core::mem::size_of::<servicepoint::Brightness>(), 1);
let data = (*brightness_grid).0.data_ref_mut();
assert_eq!(size_of::<servicepoint::Brightness>(), 1);
let data = unsafe { (*brightness_grid.as_ptr()).data_ref_mut() };
// this assumes more about the memory layout than rust guarantees. yikes!
let data: &mut [u8] = transmute(data);
SPByteSlice {
start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
length: data.len(),
}
unsafe { SPByteSlice::from_slice(transmute(data)) }
}

View file

@ -2,7 +2,6 @@
use std::ptr::NonNull;
#[repr(C)]
/// Represents a span of memory (`&mut [u8]` ) as a struct usable by C code.
///
/// You should not create an instance of this type in your C code.
@ -16,9 +15,29 @@ use std::ptr::NonNull;
/// the function returning this type.
/// - an instance of this created from C is never passed to a consuming function, as the rust code
/// will try to free the memory of a potentially separate allocator.
#[repr(C)]
pub struct SPByteSlice {
/// The start address of the memory
pub start: NonNull<u8>,
/// The amount of memory in bytes
pub length: usize,
}
impl SPByteSlice {
pub(crate) unsafe fn as_slice(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.start.as_ptr(), self.length) }
}
pub(crate) unsafe fn as_slice_mut(&self) -> &mut [u8] {
unsafe {
std::slice::from_raw_parts_mut(self.start.as_ptr(), self.length)
}
}
pub(crate) unsafe fn from_slice(slice: &mut [u8]) -> Self {
Self {
start: NonNull::new(slice.as_mut_ptr()).unwrap(),
length: slice.len(),
}
}
}

View file

@ -1,33 +1,27 @@
//! C functions for interacting with [SPCharGrid]s
//!
//! prefix `sp_char_grid_`
//!
//! A C-wrapper for grid containing UTF-8 characters.
//!
//! As the rust [char] type is not FFI-safe, characters are passed in their UTF-32 form as 32bit unsigned integers.
//!
//! The encoding is enforced in most cases by the rust standard library
//! and will panic when provided with illegal characters.
//!
//! # Examples
//!
//! ```C
//! CharGrid grid = sp_char_grid_new(4, 3);
//! sp_char_grid_fill(grid, '?');
//! sp_char_grid_set(grid, 0, 0, '!');
//! sp_char_grid_free(grid);
//! ```
use servicepoint::Grid;
use crate::SPByteSlice;
use servicepoint::{CharGrid, Grid};
use std::ptr::NonNull;
/// A C-wrapper for grid containing UTF-8 characters.
///
/// As the rust [char] type is not FFI-safe, characters are passed in their UTF-32 form as 32bit unsigned integers.
///
/// The encoding is enforced in most cases by the rust standard library
/// and will panic when provided with illegal characters.
///
/// # Examples
///
/// ```C
/// CharGrid grid = sp_char_grid_new(4, 3);
/// sp_char_grid_fill(grid, '?');
/// sp_char_grid_set(grid, 0, 0, '!');
/// sp_char_grid_free(grid);
/// ```
pub struct SPCharGrid(pub(crate) servicepoint::CharGrid);
impl Clone for SPCharGrid {
fn clone(&self) -> Self {
SPCharGrid(self.0.clone())
}
}
/// Creates a new [SPCharGrid] with the specified dimensions.
///
/// returns: [SPCharGrid] initialized to 0. Will never return NULL.
@ -42,9 +36,8 @@ impl Clone for SPCharGrid {
pub unsafe extern "C" fn sp_char_grid_new(
width: usize,
height: usize,
) -> NonNull<SPCharGrid> {
let result =
Box::new(SPCharGrid(servicepoint::CharGrid::new(width, height)));
) -> NonNull<CharGrid> {
let result = Box::new(CharGrid::new(width, height));
NonNull::from(Box::leak(result))
}
@ -70,15 +63,12 @@ pub unsafe extern "C" fn sp_char_grid_new(
pub unsafe extern "C" fn sp_char_grid_load(
width: usize,
height: usize,
data: *const u8,
data_length: usize,
) -> NonNull<SPCharGrid> {
assert!(data.is_null());
let data = std::slice::from_raw_parts(data, data_length);
let result = Box::new(SPCharGrid(
servicepoint::CharGrid::load_utf8(width, height, data.to_vec())
.unwrap(),
));
data: SPByteSlice,
) -> NonNull<CharGrid> {
let data = unsafe { data.as_slice() };
// TODO remove unwrap
let result =
Box::new(CharGrid::load_utf8(width, height, data.to_vec()).unwrap());
NonNull::from(Box::leak(result))
}
@ -100,10 +90,9 @@ pub unsafe extern "C" fn sp_char_grid_load(
/// by explicitly calling `sp_char_grid_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_char_grid_clone(
char_grid: *const SPCharGrid,
) -> NonNull<SPCharGrid> {
assert!(!char_grid.is_null());
let result = Box::new((*char_grid).clone());
char_grid: NonNull<CharGrid>,
) -> NonNull<CharGrid> {
let result = Box::new(unsafe { char_grid.as_ref().clone() });
NonNull::from(Box::leak(result))
}
@ -123,9 +112,8 @@ pub unsafe extern "C" fn sp_char_grid_clone(
///
/// [SPCommand]: [crate::SPCommand]
#[no_mangle]
pub unsafe extern "C" fn sp_char_grid_free(char_grid: *mut SPCharGrid) {
assert!(!char_grid.is_null());
_ = Box::from_raw(char_grid);
pub unsafe extern "C" fn sp_char_grid_free(char_grid: NonNull<CharGrid>) {
_ = unsafe { Box::from_raw(char_grid.as_ptr()) };
}
/// Gets the current value at the specified position.
@ -148,12 +136,11 @@ pub unsafe extern "C" fn sp_char_grid_free(char_grid: *mut SPCharGrid) {
/// - `char_grid` is not written to concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_char_grid_get(
char_grid: *const SPCharGrid,
char_grid: NonNull<CharGrid>,
x: usize,
y: usize,
) -> u32 {
assert!(!char_grid.is_null());
(*char_grid).0.get(x, y) as u32
unsafe { char_grid.as_ref().get(x, y) as u32 }
}
/// Sets the value of the specified position in the [SPCharGrid].
@ -181,13 +168,12 @@ pub unsafe extern "C" fn sp_char_grid_get(
/// [SPBitVec]: [crate::SPBitVec]
#[no_mangle]
pub unsafe extern "C" fn sp_char_grid_set(
char_grid: *mut SPCharGrid,
char_grid: NonNull<CharGrid>,
x: usize,
y: usize,
value: u32,
) {
assert!(!char_grid.is_null());
(*char_grid).0.set(x, y, char::from_u32(value).unwrap());
unsafe { (*char_grid.as_ptr()).set(x, y, char::from_u32(value).unwrap()) };
}
/// Sets the value of all cells in the [SPCharGrid].
@ -209,11 +195,10 @@ pub unsafe extern "C" fn sp_char_grid_set(
/// - `char_grid` is not written to or read from concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_char_grid_fill(
char_grid: *mut SPCharGrid,
char_grid: NonNull<CharGrid>,
value: u32,
) {
assert!(!char_grid.is_null());
(*char_grid).0.fill(char::from_u32(value).unwrap());
unsafe { (*char_grid.as_ptr()).fill(char::from_u32(value).unwrap()) };
}
/// Gets the width of the [SPCharGrid] instance.
@ -233,10 +218,9 @@ pub unsafe extern "C" fn sp_char_grid_fill(
/// - `char_grid` points to a valid [SPCharGrid]
#[no_mangle]
pub unsafe extern "C" fn sp_char_grid_width(
char_grid: *const SPCharGrid,
char_grid: NonNull<CharGrid>,
) -> usize {
assert!(!char_grid.is_null());
(*char_grid).0.width()
unsafe { char_grid.as_ref().width() }
}
/// Gets the height of the [SPCharGrid] instance.
@ -256,8 +240,7 @@ pub unsafe extern "C" fn sp_char_grid_width(
/// - `char_grid` points to a valid [SPCharGrid]
#[no_mangle]
pub unsafe extern "C" fn sp_char_grid_height(
char_grid: *const SPCharGrid,
char_grid: NonNull<CharGrid>,
) -> usize {
assert!(!char_grid.is_null());
(*char_grid).0.height()
unsafe { char_grid.as_ref().height() }
}

View file

@ -2,12 +2,12 @@
//!
//! prefix `sp_command_`
use std::ptr::{null_mut, NonNull};
use crate::{
SPBitVec, SPBitmap, SPBrightnessGrid, SPCharGrid, SPCompressionCode,
SPCp437Grid, SPPacket,
use crate::SPBitVec;
use servicepoint::{
BinaryOperation, Bitmap, BrightnessGrid, CharGrid, CompressionCode,
Cp437Grid, GlobalBrightnessCommand, Packet, TypedCommand,
};
use std::ptr::NonNull;
/// A low-level display command.
///
@ -23,13 +23,6 @@ use crate::{
/// ```
///
/// [SPConnection]: [crate::SPConnection]
pub struct SPCommand(pub(crate) servicepoint::Command);
impl Clone for SPCommand {
fn clone(&self) -> Self {
SPCommand(self.0.clone())
}
}
/// Tries to turn a [SPPacket] into a [SPCommand].
///
@ -52,12 +45,12 @@ impl Clone for SPCommand {
/// by explicitly calling `sp_command_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_command_try_from_packet(
packet: *mut SPPacket,
) -> *mut SPCommand {
let packet = *Box::from_raw(packet);
match servicepoint::Command::try_from(packet.0) {
Err(_) => null_mut(),
Ok(command) => Box::into_raw(Box::new(SPCommand(command))),
packet: NonNull<Packet>,
) -> *mut TypedCommand {
let packet = *unsafe { Box::from_raw(packet.as_ptr()) };
match servicepoint::TypedCommand::try_from(packet) {
Err(_) => std::ptr::null_mut(),
Ok(command) => Box::into_raw(Box::new(command)),
}
}
@ -79,10 +72,9 @@ pub unsafe extern "C" fn sp_command_try_from_packet(
/// by explicitly calling `sp_command_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_command_clone(
command: *const SPCommand,
) -> NonNull<SPCommand> {
assert!(!command.is_null());
let result = Box::new((*command).clone());
command: NonNull<TypedCommand>,
) -> NonNull<TypedCommand> {
let result = Box::new(unsafe { command.as_ref().clone() });
NonNull::from(Box::leak(result))
}
@ -105,8 +97,8 @@ pub unsafe extern "C" fn sp_command_clone(
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
/// by explicitly calling `sp_command_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_command_clear() -> NonNull<SPCommand> {
let result = Box::new(SPCommand(servicepoint::Command::Clear));
pub unsafe extern "C" fn sp_command_clear() -> NonNull<TypedCommand> {
let result = Box::new(servicepoint::ClearCommand.into());
NonNull::from(Box::leak(result))
}
@ -123,8 +115,8 @@ pub unsafe extern "C" fn sp_command_clear() -> NonNull<SPCommand> {
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
/// by explicitly calling `sp_command_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull<SPCommand> {
let result = Box::new(SPCommand(servicepoint::Command::HardReset));
pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull<TypedCommand> {
let result = Box::new(servicepoint::HardResetCommand.into());
NonNull::from(Box::leak(result))
}
@ -139,8 +131,8 @@ pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull<SPCommand> {
/// - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
/// by explicitly calling `sp_command_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_command_fade_out() -> NonNull<SPCommand> {
let result = Box::new(SPCommand(servicepoint::Command::FadeOut));
pub unsafe extern "C" fn sp_command_fade_out() -> NonNull<TypedCommand> {
let result = Box::new(servicepoint::FadeOutCommand.into());
NonNull::from(Box::leak(result))
}
@ -161,11 +153,10 @@ pub unsafe extern "C" fn sp_command_fade_out() -> NonNull<SPCommand> {
#[no_mangle]
pub unsafe extern "C" fn sp_command_brightness(
brightness: u8,
) -> NonNull<SPCommand> {
) -> NonNull<TypedCommand> {
let brightness = servicepoint::Brightness::try_from(brightness)
.expect("invalid brightness");
let result =
Box::new(SPCommand(servicepoint::Command::Brightness(brightness)));
let result = Box::new(GlobalBrightnessCommand::from(brightness).into());
NonNull::from(Box::leak(result))
}
@ -191,14 +182,16 @@ pub unsafe extern "C" fn sp_command_brightness(
pub unsafe extern "C" fn sp_command_char_brightness(
x: usize,
y: usize,
grid: *mut SPBrightnessGrid,
) -> NonNull<SPCommand> {
assert!(!grid.is_null());
let byte_grid = *Box::from_raw(grid);
let result = Box::new(SPCommand(servicepoint::Command::CharBrightness(
servicepoint::Origin::new(x, y),
byte_grid.0,
)));
grid: NonNull<BrightnessGrid>,
) -> NonNull<TypedCommand> {
let grid = unsafe { *Box::from_raw(grid.as_ptr()) };
let result = Box::new(
servicepoint::BrightnessGridCommand {
origin: servicepoint::Origin::new(x, y),
grid,
}
.into(),
);
NonNull::from(Box::leak(result))
}
@ -230,17 +223,17 @@ pub unsafe extern "C" fn sp_command_char_brightness(
#[no_mangle]
pub unsafe extern "C" fn sp_command_bitmap_linear(
offset: usize,
bit_vec: *mut SPBitVec,
compression: SPCompressionCode,
) -> NonNull<SPCommand> {
assert!(!bit_vec.is_null());
let bit_vec = *Box::from_raw(bit_vec);
let result = Box::new(SPCommand(servicepoint::Command::BitmapLinear(
offset,
bit_vec.into(),
compression.try_into().expect("invalid compression code"),
)));
NonNull::from(Box::leak(result))
bit_vec: NonNull<SPBitVec>,
compression: CompressionCode,
) -> *mut TypedCommand {
unsafe {
sp_command_bitmap_linear_internal(
offset,
bit_vec,
compression,
BinaryOperation::Overwrite,
)
}
}
/// Set pixel data according to an and-mask starting at the offset.
@ -271,17 +264,17 @@ pub unsafe extern "C" fn sp_command_bitmap_linear(
#[no_mangle]
pub unsafe extern "C" fn sp_command_bitmap_linear_and(
offset: usize,
bit_vec: *mut SPBitVec,
compression: SPCompressionCode,
) -> NonNull<SPCommand> {
assert!(!bit_vec.is_null());
let bit_vec = *Box::from_raw(bit_vec);
let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearAnd(
offset,
bit_vec.into(),
compression.try_into().expect("invalid compression code"),
)));
NonNull::from(Box::leak(result))
bit_vec: NonNull<SPBitVec>,
compression: CompressionCode,
) -> *mut TypedCommand {
unsafe {
sp_command_bitmap_linear_internal(
offset,
bit_vec,
compression,
BinaryOperation::Xor,
)
}
}
/// Set pixel data according to an or-mask starting at the offset.
@ -312,17 +305,17 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_and(
#[no_mangle]
pub unsafe extern "C" fn sp_command_bitmap_linear_or(
offset: usize,
bit_vec: *mut SPBitVec,
compression: SPCompressionCode,
) -> NonNull<SPCommand> {
assert!(!bit_vec.is_null());
let bit_vec = *Box::from_raw(bit_vec);
let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearOr(
offset,
bit_vec.into(),
compression.try_into().expect("invalid compression code"),
)));
NonNull::from(Box::leak(result))
bit_vec: NonNull<SPBitVec>,
compression: CompressionCode,
) -> *mut TypedCommand {
unsafe {
sp_command_bitmap_linear_internal(
offset,
bit_vec,
compression,
BinaryOperation::Or,
)
}
}
/// Set pixel data according to a xor-mask starting at the offset.
@ -353,17 +346,39 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_or(
#[no_mangle]
pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
offset: usize,
bit_vec: *mut SPBitVec,
compression: SPCompressionCode,
) -> NonNull<SPCommand> {
assert!(!bit_vec.is_null());
let bit_vec = *Box::from_raw(bit_vec);
let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearXor(
bit_vec: NonNull<SPBitVec>,
compression: CompressionCode,
) -> *mut TypedCommand {
unsafe {
sp_command_bitmap_linear_internal(
offset,
bit_vec,
compression,
BinaryOperation::Xor,
)
}
}
#[inline]
unsafe fn sp_command_bitmap_linear_internal(
offset: usize,
bit_vec: NonNull<SPBitVec>,
compression: CompressionCode,
operation: BinaryOperation,
) -> *mut TypedCommand {
let bit_vec = unsafe { *Box::from_raw(bit_vec.as_ptr()) };
let compression = match compression.try_into() {
Ok(compression) => compression,
Err(_) => return std::ptr::null_mut(),
};
let command = servicepoint::BitVecCommand {
offset,
bit_vec.into(),
compression.try_into().expect("invalid compression code"),
)));
NonNull::from(Box::leak(result))
operation,
bitvec: bit_vec.0,
compression,
}
.into();
Box::leak(Box::new(command))
}
/// Show codepage 437 encoded text on the screen.
@ -388,14 +403,16 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
pub unsafe extern "C" fn sp_command_cp437_data(
x: usize,
y: usize,
grid: *mut SPCp437Grid,
) -> NonNull<SPCommand> {
assert!(!grid.is_null());
let grid = *Box::from_raw(grid);
let result = Box::new(SPCommand(servicepoint::Command::Cp437Data(
servicepoint::Origin::new(x, y),
grid.0,
)));
grid: NonNull<Cp437Grid>,
) -> NonNull<TypedCommand> {
let grid = *unsafe { Box::from_raw(grid.as_ptr()) };
let result = Box::new(
servicepoint::Cp437GridCommand {
origin: servicepoint::Origin::new(x, y),
grid,
}
.into(),
);
NonNull::from(Box::leak(result))
}
@ -421,14 +438,16 @@ pub unsafe extern "C" fn sp_command_cp437_data(
pub unsafe extern "C" fn sp_command_utf8_data(
x: usize,
y: usize,
grid: *mut SPCharGrid,
) -> NonNull<SPCommand> {
assert!(!grid.is_null());
let grid = *Box::from_raw(grid);
let result = Box::new(SPCommand(servicepoint::Command::Utf8Data(
servicepoint::Origin::new(x, y),
grid.0,
)));
grid: NonNull<CharGrid>,
) -> NonNull<TypedCommand> {
let grid = unsafe { *Box::from_raw(grid.as_ptr()) };
let result = Box::new(
servicepoint::CharGridCommand {
origin: servicepoint::Origin::new(x, y),
grid,
}
.into(),
);
NonNull::from(Box::leak(result))
}
@ -456,19 +475,21 @@ pub unsafe extern "C" fn sp_command_utf8_data(
pub unsafe extern "C" fn sp_command_bitmap_linear_win(
x: usize,
y: usize,
bitmap: *mut SPBitmap,
compression_code: SPCompressionCode,
) -> NonNull<SPCommand> {
assert!(!bitmap.is_null());
let byte_grid = (*Box::from_raw(bitmap)).0;
let result = Box::new(SPCommand(servicepoint::Command::BitmapLinearWin(
servicepoint::Origin::new(x, y),
byte_grid,
compression_code
.try_into()
.expect("invalid compression code"),
)));
NonNull::from(Box::leak(result))
bitmap: NonNull<Bitmap>,
compression: CompressionCode,
) -> *mut TypedCommand {
let bitmap = unsafe { *Box::from_raw(bitmap.as_ptr()) };
let compression = match compression.try_into() {
Ok(compression) => compression,
Err(_) => return std::ptr::null_mut(),
};
let command = servicepoint::BitmapCommand {
origin: servicepoint::Origin::new(x, y),
bitmap,
compression,
}
.into();
Box::leak(Box::new(command))
}
/// Deallocates a [SPCommand].
@ -492,7 +513,6 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_win(
/// - `command` is not used concurrently or after this call
/// - `command` was not passed to another consuming function, e.g. to create a [SPPacket]
#[no_mangle]
pub unsafe extern "C" fn sp_command_free(command: *mut SPCommand) {
assert!(!command.is_null());
_ = Box::from_raw(command);
pub unsafe extern "C" fn sp_command_free(command: NonNull<TypedCommand>) {
_ = unsafe { Box::from_raw(command.as_ptr()) };
}

View file

@ -1,22 +1,20 @@
//! C functions for interacting with [SPConnection]s
//!
//! prefix `sp_connection_`
//!
//! A connection to the display.
//!
//! # Examples
//!
//! ```C
//! CConnection connection = sp_connection_open("172.23.42.29:2342");
//! if (connection != NULL)
//! sp_connection_send_command(connection, sp_command_clear());
//! ```
use servicepoint::{Connection, Packet, TypedCommand, UdpConnection};
use std::ffi::{c_char, CStr};
use std::ptr::{null_mut, NonNull};
use crate::{SPCommand, SPPacket};
/// A connection to the display.
///
/// # Examples
///
/// ```C
/// CConnection connection = sp_connection_open("172.23.42.29:2342");
/// if (connection != NULL)
/// sp_connection_send_command(connection, sp_command_clear());
/// ```
pub struct SPConnection(pub(crate) servicepoint::Connection);
use std::ptr::NonNull;
/// Creates a new instance of [SPConnection].
///
@ -34,33 +32,46 @@ pub struct SPConnection(pub(crate) servicepoint::Connection);
/// by explicitly calling `sp_connection_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_connection_open(
host: *const c_char,
) -> *mut SPConnection {
assert!(!host.is_null());
let host = CStr::from_ptr(host).to_str().expect("Bad encoding");
let connection = match servicepoint::Connection::open(host) {
Err(_) => return null_mut(),
host: NonNull<c_char>,
) -> *mut UdpConnection {
let host = unsafe { CStr::from_ptr(host.as_ptr()) }
.to_str()
.expect("Bad encoding");
let connection = match UdpConnection::open(host) {
Err(_) => return std::ptr::null_mut(),
Ok(value) => value,
};
Box::into_raw(Box::new(SPConnection(connection)))
Box::into_raw(Box::new(connection))
}
/// Creates a new instance of [SPConnection] for testing that does not actually send anything.
///
/// returns: a new instance. Will never return NULL.
///
/// # Safety
///
/// The caller has to make sure that:
///
/// - the returned instance is freed in some way, either by using a consuming function or
/// by explicitly calling `sp_connection_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_connection_fake() -> NonNull<SPConnection> {
let result = Box::new(SPConnection(servicepoint::Connection::Fake));
NonNull::from(Box::leak(result))
}
//#[no_mangle]
//pub unsafe extern "C" fn sp_connection_open_ipv4(
// host: SocketAddrV4,
//) -> *mut SPConnection {
// let connection = match servicepoint::UdpConnection::open(host) {
// Err(_) => return std::ptr::null_mut(),
// Ok(value) => value,
// };
//
// Box::into_raw(Box::new(SPConnection(connection)))
//}
// /// Creates a new instance of [SPUdpConnection] for testing that does not actually send anything.
// ///
// /// returns: a new instance. Will never return NULL.
// ///
// /// # Safety
// ///
// /// The caller has to make sure that:
// ///
// /// - the returned instance is freed in some way, either by using a consuming function or
// /// by explicitly calling `sp_connection_free`.
// #[no_mangle]
// pub unsafe extern "C" fn sp_connection_fake() -> NonNull<SPUdpConnection> {
// let result = Box::new(SPUdpConnection(servicepoint::Connection::Fake));
// NonNull::from(Box::leak(result))
// }
/// Sends a [SPPacket] to the display using the [SPConnection].
///
@ -82,13 +93,11 @@ pub unsafe extern "C" fn sp_connection_fake() -> NonNull<SPConnection> {
/// - `packet` is not used concurrently or after this call
#[no_mangle]
pub unsafe extern "C" fn sp_connection_send_packet(
connection: *const SPConnection,
packet: *mut SPPacket,
connection: NonNull<UdpConnection>,
packet: NonNull<Packet>,
) -> bool {
assert!(!connection.is_null());
assert!(!packet.is_null());
let packet = Box::from_raw(packet);
(*connection).0.send((*packet).0).is_ok()
let packet = unsafe { Box::from_raw(packet.as_ptr()) };
unsafe { connection.as_ref().send(*packet) }.is_ok()
}
/// Sends a [SPCommand] to the display using the [SPConnection].
@ -111,13 +120,11 @@ pub unsafe extern "C" fn sp_connection_send_packet(
/// - `command` is not used concurrently or after this call
#[no_mangle]
pub unsafe extern "C" fn sp_connection_send_command(
connection: *const SPConnection,
command: *mut SPCommand,
connection: NonNull<UdpConnection>,
command: NonNull<TypedCommand>,
) -> bool {
assert!(!connection.is_null());
assert!(!command.is_null());
let command = (*Box::from_raw(command)).0;
(*connection).0.send(command).is_ok()
let command = *unsafe { Box::from_raw(command.as_ptr()) };
unsafe { connection.as_ref().send(command) }.is_ok()
}
/// Closes and deallocates a [SPConnection].
@ -133,7 +140,8 @@ pub unsafe extern "C" fn sp_connection_send_command(
/// - `connection` points to a valid [SPConnection]
/// - `connection` is not used concurrently or after this call
#[no_mangle]
pub unsafe extern "C" fn sp_connection_free(connection: *mut SPConnection) {
assert!(!connection.is_null());
_ = Box::from_raw(connection);
pub unsafe extern "C" fn sp_connection_free(
connection: NonNull<UdpConnection>,
) {
_ = unsafe { Box::from_raw(connection.as_ptr()) };
}

View file

@ -1,48 +0,0 @@
//! re-exported constants for use in C
use servicepoint::CompressionCode;
use std::time::Duration;
/// size of a single tile in one dimension
pub const SP_TILE_SIZE: usize = 8;
/// Display tile count in the x-direction
pub const SP_TILE_WIDTH: usize = 56;
/// Display tile count in the y-direction
pub const SP_TILE_HEIGHT: usize = 20;
/// Display width in pixels
pub const SP_PIXEL_WIDTH: usize = SP_TILE_WIDTH * SP_TILE_SIZE;
/// Display height in pixels
pub const SP_PIXEL_HEIGHT: usize = SP_TILE_HEIGHT * SP_TILE_SIZE;
/// pixel count on whole screen
pub const SP_PIXEL_COUNT: usize = SP_PIXEL_WIDTH * SP_PIXEL_HEIGHT;
/// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets.
pub const SP_FRAME_PACING_MS: u128 = Duration::from_millis(30).as_millis();
/// Specifies the kind of compression to use.
#[repr(u16)]
pub enum SPCompressionCode {
/// no compression
Uncompressed = 0x0,
/// compress using flate2 with zlib header
Zlib = 0x677a,
/// compress using bzip2
Bzip2 = 0x627a,
/// compress using lzma
Lzma = 0x6c7a,
/// compress using Zstandard
Zstd = 0x7a73,
}
impl TryFrom<SPCompressionCode> for CompressionCode {
type Error = ();
fn try_from(value: SPCompressionCode) -> Result<Self, Self::Error> {
CompressionCode::try_from(value as u16)
}
}

View file

@ -1,31 +1,25 @@
//! C functions for interacting with [SPCp437Grid]s
//!
//! prefix `sp_cp437_grid_`
//!
//!
//! A C-wrapper for grid containing codepage 437 characters.
//!
//! The encoding is currently not enforced.
//!
//! # Examples
//!
//! ```C
//! Cp437Grid grid = sp_cp437_grid_new(4, 3);
//! sp_cp437_grid_fill(grid, '?');
//! sp_cp437_grid_set(grid, 0, 0, '!');
//! sp_cp437_grid_free(grid);
//! ```
use crate::SPByteSlice;
use servicepoint::{DataRef, Grid};
use servicepoint::{Cp437Grid, DataRef, Grid};
use std::ptr::NonNull;
/// A C-wrapper for grid containing codepage 437 characters.
///
/// The encoding is currently not enforced.
///
/// # Examples
///
/// ```C
/// Cp437Grid grid = sp_cp437_grid_new(4, 3);
/// sp_cp437_grid_fill(grid, '?');
/// sp_cp437_grid_set(grid, 0, 0, '!');
/// sp_cp437_grid_free(grid);
/// ```
pub struct SPCp437Grid(pub(crate) servicepoint::Cp437Grid);
impl Clone for SPCp437Grid {
fn clone(&self) -> Self {
SPCp437Grid(self.0.clone())
}
}
/// Creates a new [SPCp437Grid] with the specified dimensions.
///
/// returns: [SPCp437Grid] initialized to 0. Will never return NULL.
@ -40,9 +34,8 @@ impl Clone for SPCp437Grid {
pub unsafe extern "C" fn sp_cp437_grid_new(
width: usize,
height: usize,
) -> NonNull<SPCp437Grid> {
let result =
Box::new(SPCp437Grid(servicepoint::Cp437Grid::new(width, height)));
) -> NonNull<Cp437Grid> {
let result = Box::new(Cp437Grid::new(width, height));
NonNull::from(Box::leak(result))
}
@ -67,15 +60,15 @@ pub unsafe extern "C" fn sp_cp437_grid_new(
pub unsafe extern "C" fn sp_cp437_grid_load(
width: usize,
height: usize,
data: *const u8,
data_length: usize,
) -> NonNull<SPCp437Grid> {
assert!(data.is_null());
let data = std::slice::from_raw_parts(data, data_length);
let result = Box::new(SPCp437Grid(servicepoint::Cp437Grid::load(
width, height, data,
)));
NonNull::from(Box::leak(result))
data: SPByteSlice,
) -> *mut Cp437Grid {
let data = unsafe { data.as_slice() };
let grid = Cp437Grid::load(width, height, data);
if let Some(grid) = grid {
Box::leak(Box::new(grid))
} else {
std::ptr::null_mut()
}
}
/// Clones a [SPCp437Grid].
@ -96,10 +89,9 @@ pub unsafe extern "C" fn sp_cp437_grid_load(
/// by explicitly calling `sp_cp437_grid_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_cp437_grid_clone(
cp437_grid: *const SPCp437Grid,
) -> NonNull<SPCp437Grid> {
assert!(!cp437_grid.is_null());
let result = Box::new((*cp437_grid).clone());
cp437_grid: NonNull<Cp437Grid>,
) -> NonNull<Cp437Grid> {
let result = Box::new(unsafe { cp437_grid.as_ref().clone() });
NonNull::from(Box::leak(result))
}
@ -119,9 +111,8 @@ pub unsafe extern "C" fn sp_cp437_grid_clone(
///
/// [SPCommand]: [crate::SPCommand]
#[no_mangle]
pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) {
assert!(!cp437_grid.is_null());
_ = Box::from_raw(cp437_grid);
pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: NonNull<Cp437Grid>) {
_ = unsafe { Box::from_raw(cp437_grid.as_ptr()) };
}
/// Gets the current value at the specified position.
@ -144,12 +135,11 @@ pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) {
/// - `cp437_grid` is not written to concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_cp437_grid_get(
cp437_grid: *const SPCp437Grid,
cp437_grid: NonNull<Cp437Grid>,
x: usize,
y: usize,
) -> u8 {
assert!(!cp437_grid.is_null());
(*cp437_grid).0.get(x, y)
unsafe { cp437_grid.as_ref().get(x, y) }
}
/// Sets the value of the specified position in the [SPCp437Grid].
@ -177,13 +167,12 @@ pub unsafe extern "C" fn sp_cp437_grid_get(
/// [SPBitVec]: [crate::SPBitVec]
#[no_mangle]
pub unsafe extern "C" fn sp_cp437_grid_set(
cp437_grid: *mut SPCp437Grid,
cp437_grid: NonNull<Cp437Grid>,
x: usize,
y: usize,
value: u8,
) {
assert!(!cp437_grid.is_null());
(*cp437_grid).0.set(x, y, value);
unsafe { (*cp437_grid.as_ptr()).set(x, y, value) };
}
/// Sets the value of all cells in the [SPCp437Grid].
@ -205,11 +194,10 @@ pub unsafe extern "C" fn sp_cp437_grid_set(
/// - `cp437_grid` is not written to or read from concurrently
#[no_mangle]
pub unsafe extern "C" fn sp_cp437_grid_fill(
cp437_grid: *mut SPCp437Grid,
cp437_grid: NonNull<Cp437Grid>,
value: u8,
) {
assert!(!cp437_grid.is_null());
(*cp437_grid).0.fill(value);
unsafe { (*cp437_grid.as_ptr()).fill(value) };
}
/// Gets the width of the [SPCp437Grid] instance.
@ -229,10 +217,9 @@ pub unsafe extern "C" fn sp_cp437_grid_fill(
/// - `cp437_grid` points to a valid [SPCp437Grid]
#[no_mangle]
pub unsafe extern "C" fn sp_cp437_grid_width(
cp437_grid: *const SPCp437Grid,
cp437_grid: NonNull<Cp437Grid>,
) -> usize {
assert!(!cp437_grid.is_null());
(*cp437_grid).0.width()
unsafe { cp437_grid.as_ref().width() }
}
/// Gets the height of the [SPCp437Grid] instance.
@ -252,10 +239,9 @@ pub unsafe extern "C" fn sp_cp437_grid_width(
/// - `cp437_grid` points to a valid [SPCp437Grid]
#[no_mangle]
pub unsafe extern "C" fn sp_cp437_grid_height(
cp437_grid: *const SPCp437Grid,
cp437_grid: NonNull<Cp437Grid>,
) -> usize {
assert!(!cp437_grid.is_null());
(*cp437_grid).0.height()
unsafe { cp437_grid.as_ref().height() }
}
/// Gets an unsafe reference to the data of the [SPCp437Grid] instance.
@ -275,11 +261,7 @@ pub unsafe extern "C" fn sp_cp437_grid_height(
/// - the returned memory range is never accessed concurrently, either via the [SPCp437Grid] or directly
#[no_mangle]
pub unsafe extern "C" fn sp_cp437_grid_unsafe_data_ref(
cp437_grid: *mut SPCp437Grid,
cp437_grid: NonNull<Cp437Grid>,
) -> SPByteSlice {
let data = (*cp437_grid).0.data_ref_mut();
SPByteSlice {
start: NonNull::new(data.as_mut_ptr_range().start).unwrap(),
length: data.len(),
}
unsafe { SPByteSlice::from_slice((*cp437_grid.as_ptr()).data_ref_mut()) }
}

View file

@ -32,7 +32,6 @@ pub use crate::byte_slice::*;
pub use crate::char_grid::*;
pub use crate::command::*;
pub use crate::connection::*;
pub use crate::constants::*;
pub use crate::cp437_grid::*;
pub use crate::packet::*;
@ -43,6 +42,10 @@ mod byte_slice;
mod char_grid;
mod command;
mod connection;
mod constants;
mod cp437_grid;
mod packet;
use std::time::Duration;
/// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets.
pub const SP_FRAME_PACING_MS: u128 = Duration::from_millis(30).as_millis();

View file

@ -1,13 +1,13 @@
//! C functions for interacting with [SPPacket]s
//!
//! prefix `sp_packet_`
//!
//!
//! The raw packet
use std::ptr::{null_mut, NonNull};
use crate::SPCommand;
/// The raw packet
pub struct SPPacket(pub(crate) servicepoint::Packet);
use crate::SPByteSlice;
use servicepoint::{Header, Packet, TypedCommand};
use std::ptr::NonNull;
/// Turns a [SPCommand] into a [SPPacket].
/// The [SPCommand] gets consumed.
@ -28,12 +28,14 @@ pub struct SPPacket(pub(crate) servicepoint::Packet);
/// by explicitly calling `sp_packet_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_packet_from_command(
command: *mut SPCommand,
) -> NonNull<SPPacket> {
assert!(!command.is_null());
let command = *Box::from_raw(command);
let result = Box::new(SPPacket(command.0.into()));
NonNull::from(Box::leak(result))
command: NonNull<TypedCommand>,
) -> *mut Packet {
let command = unsafe { *Box::from_raw(command.as_ptr()) };
if let Ok(packet) = command.try_into() {
Box::leak(Box::new(packet))
} else {
std::ptr::null_mut()
}
}
/// Tries to load a [SPPacket] from the passed array with the specified length.
@ -53,15 +55,11 @@ pub unsafe extern "C" fn sp_packet_from_command(
/// - the returned [SPPacket] instance is freed in some way, either by using a consuming function or
/// by explicitly calling `sp_packet_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_packet_try_load(
data: *const u8,
length: usize,
) -> *mut SPPacket {
assert!(!data.is_null());
let data = std::slice::from_raw_parts(data, length);
pub unsafe extern "C" fn sp_packet_try_load(data: SPByteSlice) -> *mut Packet {
let data = unsafe { data.as_slice() };
match servicepoint::Packet::try_from(data) {
Err(_) => null_mut(),
Ok(packet) => Box::into_raw(Box::new(SPPacket(packet))),
Err(_) => std::ptr::null_mut(),
Ok(packet) => Box::into_raw(Box::new(packet)),
}
}
@ -91,35 +89,50 @@ pub unsafe extern "C" fn sp_packet_try_load(
/// by explicitly calling [sp_packet_free].
#[no_mangle]
pub unsafe extern "C" fn sp_packet_from_parts(
command_code: u16,
a: u16,
b: u16,
c: u16,
d: u16,
payload: *const u8,
payload_len: usize,
) -> NonNull<SPPacket> {
assert_eq!(payload.is_null(), payload_len == 0);
header: Header,
payload: *const SPByteSlice,
) -> NonNull<Packet> {
let payload = if payload.is_null() {
vec![]
} else {
let payload = std::slice::from_raw_parts(payload, payload_len);
let payload = unsafe { (*payload).as_slice() };
Vec::from(payload)
};
let packet = servicepoint::Packet {
header: servicepoint::Header {
command_code,
a,
b,
c,
d,
},
payload,
};
let result = Box::new(SPPacket(packet));
NonNull::from(Box::leak(result))
let packet = Box::new(Packet { header, payload });
NonNull::from(Box::leak(packet))
}
#[no_mangle]
pub unsafe extern "C" fn sp_packet_get_header(
packet: NonNull<Packet>,
) -> NonNull<Header> {
NonNull::from(&mut unsafe { (*packet.as_ptr()).header })
}
#[no_mangle]
pub unsafe extern "C" fn sp_packet_get_payload(
packet: NonNull<Packet>,
) -> SPByteSlice {
unsafe { SPByteSlice::from_slice(&mut *(*packet.as_ptr()).payload) }
}
#[no_mangle]
pub unsafe extern "C" fn sp_packet_set_payload(
packet: NonNull<Packet>,
data: SPByteSlice,
) {
unsafe { (*packet.as_ptr()).payload = data.as_slice().to_vec() }
}
#[no_mangle]
pub unsafe extern "C" fn sp_packet_write_to(
packet: NonNull<Packet>,
buffer: SPByteSlice,
) {
unsafe {
packet.as_ref().serialize_to(buffer.as_slice_mut());
}
}
/// Clones a [SPPacket].
@ -140,10 +153,9 @@ pub unsafe extern "C" fn sp_packet_from_parts(
/// by explicitly calling `sp_packet_free`.
#[no_mangle]
pub unsafe extern "C" fn sp_packet_clone(
packet: *const SPPacket,
) -> NonNull<SPPacket> {
assert!(!packet.is_null());
let result = Box::new(SPPacket((*packet).0.clone()));
packet: NonNull<Packet>,
) -> NonNull<Packet> {
let result = Box::new(unsafe { packet.as_ref().clone() });
NonNull::from(Box::leak(result))
}
@ -160,7 +172,6 @@ pub unsafe extern "C" fn sp_packet_clone(
/// - `packet` points to a valid [SPPacket]
/// - `packet` is not used concurrently or after this call
#[no_mangle]
pub unsafe extern "C" fn sp_packet_free(packet: *mut SPPacket) {
assert!(!packet.is_null());
_ = Box::from_raw(packet)
pub unsafe extern "C" fn sp_packet_free(packet: NonNull<Packet>) {
_ = unsafe { Box::from_raw(packet.as_ptr()) }
}