mirror of
https://github.com/cccb/servicepoint.git
synced 2025-01-18 10:00:14 +01:00
Merge pull request #10 from cccb/improve-binding-docs
Improve binding documentation
This commit is contained in:
commit
c5cb6475b2
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@ out
|
|||
bin
|
||||
obj
|
||||
.direnv
|
||||
.envrc
|
||||
|
|
28
CONTRIBUTING.md
Normal file
28
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Contributing
|
||||
|
||||
Contributions are accepted in any form (issues, documentation, feature requests, code, review, ...).
|
||||
|
||||
All creatures welcome.
|
||||
|
||||
## Pull requests
|
||||
|
||||
Feel free to create a PR, even if your change is not done yet.
|
||||
|
||||
Mark your PR as a draft as long as you do not want it to be merged.
|
||||
|
||||
The main branch is supposed to be a working version, including language bindings,
|
||||
which means sometimes your PR may be merged into a temporary development branch.
|
||||
|
||||
Unit tests and documentation are required for the core library.
|
||||
|
||||
## Language bindings
|
||||
|
||||
Pull requests for your preferred language will be accepted.
|
||||
If there is no code generator, it should call the C ABI methods provided by `servicepoint_binding_c`.
|
||||
It should be able to send most of the basic commands in a way the simulator accepts, receiving is
|
||||
not required for the merge.
|
||||
|
||||
It is okay for the feature set of a language binding to lag behind the one of the rust crate.
|
||||
This also means you do not have to expose a feature to all the language bindings when adding something to the core.
|
||||
|
||||
If your change may break other language bindings, please note that in your PR description so someone can check them.
|
441
Cargo.lock
generated
441
Cargo.lock
generated
|
@ -3,10 +3,10 @@
|
|||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
|
@ -19,9 +19,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.14"
|
||||
version = "0.6.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
|
||||
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
|
@ -34,61 +34,38 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.7"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
|
||||
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
|
||||
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.3"
|
||||
version = "3.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
|
||||
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[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.6.0"
|
||||
|
@ -107,6 +84,12 @@ dependencies = [
|
|||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bzip2"
|
||||
version = "0.4.4"
|
||||
|
@ -130,11 +113,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cbindgen"
|
||||
version = "0.26.0"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49"
|
||||
checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb"
|
||||
dependencies = [
|
||||
"clap 3.2.25",
|
||||
"clap",
|
||||
"heck 0.4.1",
|
||||
"indexmap",
|
||||
"log",
|
||||
|
@ -142,20 +125,20 @@ dependencies = [
|
|||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 1.0.109",
|
||||
"syn",
|
||||
"tempfile",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.101"
|
||||
version = "1.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d"
|
||||
checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -166,24 +149,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.25"
|
||||
version = "4.5.17"
|
||||
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.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
|
||||
checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -191,48 +159,39 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.7"
|
||||
version = "4.5.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
|
||||
checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex 0.7.1",
|
||||
"strsim 0.11.1",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.5"
|
||||
version = "4.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
|
||||
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.4"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
|
||||
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
|
@ -245,14 +204,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "csbindgen"
|
||||
version = "1.9.1"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf70eb656f35e0e6956cbde31c66431c53d8a546823489719099c71525767a9c"
|
||||
checksum = "c26b9831049b947d154bba920e4124053def72447be6fb106a96f483874b482a"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"syn 1.0.109",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.9"
|
||||
|
@ -260,20 +225,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.1.0"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
|
||||
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.30"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
|
||||
checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
|
@ -298,9 +263,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
|
@ -314,30 +279,21 @@ version = "0.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.0"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
|
@ -347,9 +303,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
|||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.31"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
|
||||
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
@ -364,9 +320,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
version = "0.2.158"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
|
@ -376,9 +332,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
|||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.21"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
|
@ -388,11 +344,11 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
|||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.4"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
|
||||
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -401,12 +357,6 @@ 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"
|
||||
|
@ -415,9 +365,12 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
|||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
|
@ -430,9 +383,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -475,9 +428,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.5"
|
||||
version = "1.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
|
||||
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -514,15 +467,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.34"
|
||||
version = "0.38.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||
checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -533,42 +486,52 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.118"
|
||||
version = "1.0.128"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4"
|
||||
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servicepoint"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"bzip2",
|
||||
"clap 4.5.7",
|
||||
"clap",
|
||||
"flate2",
|
||||
"log",
|
||||
"rand",
|
||||
|
@ -578,7 +541,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "servicepoint_binding_c"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"servicepoint",
|
||||
|
@ -586,7 +549,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "servicepoint_binding_cs"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"csbindgen",
|
||||
"servicepoint",
|
||||
|
@ -594,10 +557,10 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
|
@ -607,20 +570,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
version = "2.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -635,38 +587,49 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
|||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.10.1"
|
||||
version = "3.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||
checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[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"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
|
||||
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.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -693,37 +656,6 @@ 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"
|
||||
|
@ -734,10 +666,19 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.5"
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
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",
|
||||
|
@ -751,51 +692,60 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
|
@ -807,28 +757,49 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.1"
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "7.1.0"
|
||||
version = "7.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a"
|
||||
checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059"
|
||||
dependencies = [
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.11+zstd.1.5.6"
|
||||
version = "2.0.13+zstd.1.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75652c55c0b6f3e6f12eb786fe1bc960396bf05a1eb3bf1f3691c3610ac2e6d4"
|
||||
checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
|
|
|
@ -6,7 +6,7 @@ members = [
|
|||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
|
||||
[workspace.lints.rust]
|
||||
missing-docs = "warn"
|
||||
|
|
65
README.md
65
README.md
|
@ -7,70 +7,29 @@ programming languages.
|
|||
|
||||
Take a look at the contained crates for language specific information:
|
||||
|
||||
| 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) |
|
||||
| Language | Readme |
|
||||
|-----------|---------------------------------------------------------------------|
|
||||
| Rust | [servicepoint](crates/servicepoint/README.md) |
|
||||
| C / C++ | [servicepoint_binding_c](crates/servicepoint_binding_c/README.md) |
|
||||
| .NET (C#) | [servicepoint_binding_cs](crates/servicepoint_binding_cs/README.md) |
|
||||
|
||||
## Projects using the library
|
||||
|
||||
- screen simulator (rust): [servicepoint-simulator](https://github.com/kaesaecracker/servicepoint-simulator)
|
||||
- A bunch of projects (C): [arfst23/ServicePoint](https://github.com/arfst23/ServicePoint), including
|
||||
- a CLI tool to display image files on the display or use the display as a TTY
|
||||
- a BSD games robots clone
|
||||
- a split-flap-display simulator
|
||||
- animations that play on the display
|
||||
- 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.
|
||||
|
||||
## About the display
|
||||
## Contributing
|
||||
|
||||
- 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.
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
## What happened to servicepoint2?
|
||||
|
||||
After `servicepoint2` has been merged into `servicepoint`, `servicepoint2` will not continue to get any updates.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are accepted in any form (issues, documentation, feature requests, code, review, ...).
|
||||
|
||||
All creatures welcome.
|
||||
|
|
41
about_display.md
Normal file
41
about_display.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
# About the display
|
||||
|
||||
- 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.
|
||||
|
||||
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.
|
|
@ -46,7 +46,7 @@ In the likely case you only need one of them, you can include that one specifica
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
servicepoint = { version = "0.7.0", default-features = false, features = ["compression-bz"] }
|
||||
servicepoint = { version = "0.8.0", default-features = false, features = ["compression-bz"] }
|
||||
```
|
||||
|
||||
## Everything else
|
||||
|
|
|
@ -190,10 +190,15 @@ impl TryFrom<Packet> for Command {
|
|||
|
||||
/// Try to interpret the `Packet` as one containing a `Command`
|
||||
fn try_from(packet: Packet) -> Result<Self, Self::Error> {
|
||||
let Packet(Header(command_u16, a, _, _, _), _) = packet;
|
||||
let command_code = match CommandCode::try_from(command_u16) {
|
||||
let Packet {
|
||||
header: Header {
|
||||
command_code, a, ..
|
||||
},
|
||||
..
|
||||
} = packet;
|
||||
let command_code = match CommandCode::try_from(command_code) {
|
||||
Err(()) => {
|
||||
return Err(TryFromPacketError::InvalidCommand(command_u16));
|
||||
return Err(TryFromPacketError::InvalidCommand(command_code));
|
||||
}
|
||||
Ok(value) => value,
|
||||
};
|
||||
|
@ -266,8 +271,17 @@ impl Command {
|
|||
packet: Packet,
|
||||
compression: CompressionCode,
|
||||
) -> Result<Command, TryFromPacketError> {
|
||||
let Packet(Header(_, tiles_x, pixels_y, tile_w, pixel_h), payload) =
|
||||
packet;
|
||||
let Packet {
|
||||
header:
|
||||
Header {
|
||||
command_code: _,
|
||||
a: tiles_x,
|
||||
b: pixels_y,
|
||||
c: tile_w,
|
||||
d: pixel_h,
|
||||
},
|
||||
payload,
|
||||
} = packet;
|
||||
|
||||
let payload = match into_decompressed(compression, payload) {
|
||||
None => return Err(TryFromPacketError::DecompressionFailed),
|
||||
|
@ -290,7 +304,17 @@ impl Command {
|
|||
packet: Packet,
|
||||
command: Command,
|
||||
) -> Result<Command, TryFromPacketError> {
|
||||
let Packet(Header(_, a, b, c, d), payload) = packet;
|
||||
let Packet {
|
||||
header:
|
||||
Header {
|
||||
command_code: _,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
d,
|
||||
},
|
||||
payload,
|
||||
} = packet;
|
||||
if !payload.is_empty() {
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(0, payload.len()))
|
||||
} else if a != 0 || b != 0 || c != 0 || d != 0 {
|
||||
|
@ -304,7 +328,16 @@ impl Command {
|
|||
fn packet_into_linear_bitmap(
|
||||
packet: Packet,
|
||||
) -> Result<(SpBitVec, CompressionCode), TryFromPacketError> {
|
||||
let Packet(Header(_, _, length, sub, reserved), payload) = packet;
|
||||
let Packet {
|
||||
header:
|
||||
Header {
|
||||
b: length,
|
||||
c: sub,
|
||||
d: reserved,
|
||||
..
|
||||
},
|
||||
payload,
|
||||
} = packet;
|
||||
if reserved != 0 {
|
||||
return Err(TryFromPacketError::ExtraneousHeaderValues);
|
||||
}
|
||||
|
@ -330,7 +363,17 @@ impl Command {
|
|||
fn packet_into_char_brightness(
|
||||
packet: &Packet,
|
||||
) -> Result<Command, TryFromPacketError> {
|
||||
let Packet(Header(_, x, y, width, height), payload) = packet;
|
||||
let Packet {
|
||||
header:
|
||||
Header {
|
||||
command_code: _,
|
||||
a: x,
|
||||
b: y,
|
||||
c: width,
|
||||
d: height,
|
||||
},
|
||||
payload,
|
||||
} = packet;
|
||||
|
||||
let grid =
|
||||
PrimitiveGrid::load(*width as usize, *height as usize, payload);
|
||||
|
@ -348,7 +391,17 @@ impl Command {
|
|||
fn packet_into_brightness(
|
||||
packet: &Packet,
|
||||
) -> Result<Command, TryFromPacketError> {
|
||||
let Packet(Header(_, a, b, c, d), payload) = packet;
|
||||
let Packet {
|
||||
header:
|
||||
Header {
|
||||
command_code: _,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
d,
|
||||
},
|
||||
payload,
|
||||
} = packet;
|
||||
if payload.len() != 1 {
|
||||
return Err(TryFromPacketError::UnexpectedPayloadSize(
|
||||
1,
|
||||
|
@ -369,7 +422,17 @@ impl Command {
|
|||
fn packet_into_cp437(
|
||||
packet: &Packet,
|
||||
) -> Result<Command, TryFromPacketError> {
|
||||
let Packet(Header(_, a, b, c, d), payload) = packet;
|
||||
let Packet {
|
||||
header:
|
||||
Header {
|
||||
command_code: _,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
d,
|
||||
},
|
||||
payload,
|
||||
} = packet;
|
||||
Ok(Command::Cp437Data(
|
||||
Origin::new(*a as usize, *b as usize),
|
||||
Cp437Grid::load(*c as usize, *d as usize, payload),
|
||||
|
@ -483,7 +546,16 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn error_invalid_command() {
|
||||
let p = Packet(Header(0xFF, 0x00, 0x00, 0x00, 0x00), vec![]);
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: 0xFF,
|
||||
a: 0x00,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = Command::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
|
@ -493,10 +565,16 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn error_extraneous_header_values_clear() {
|
||||
let p = Packet(
|
||||
Header(CommandCode::Clear.into(), 0x05, 0x00, 0x00, 0x00),
|
||||
vec![],
|
||||
);
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Clear.into(),
|
||||
a: 0x05,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = Command::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
|
@ -506,10 +584,16 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn error_extraneous_header_values_brightness() {
|
||||
let p = Packet(
|
||||
Header(CommandCode::Brightness.into(), 0x00, 0x13, 0x37, 0x00),
|
||||
vec![5],
|
||||
);
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
a: 0x00,
|
||||
b: 0x13,
|
||||
c: 0x37,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![5],
|
||||
};
|
||||
let result = Command::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
|
@ -519,10 +603,16 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn error_extraneous_header_hard_reset() {
|
||||
let p = Packet(
|
||||
Header(CommandCode::HardReset.into(), 0x00, 0x00, 0x00, 0x01),
|
||||
vec![],
|
||||
);
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::HardReset.into(),
|
||||
a: 0x00,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x01,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = Command::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
|
@ -532,10 +622,16 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn error_extraneous_header_fade_out() {
|
||||
let p = Packet(
|
||||
Header(CommandCode::FadeOut.into(), 0x10, 0x00, 0x00, 0x01),
|
||||
vec![],
|
||||
);
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::FadeOut.into(),
|
||||
a: 0x10,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x01,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = Command::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
|
@ -545,10 +641,16 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn error_unexpected_payload() {
|
||||
let p = Packet(
|
||||
Header(CommandCode::FadeOut.into(), 0x00, 0x00, 0x00, 0x00),
|
||||
vec![5, 7],
|
||||
);
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::FadeOut.into(),
|
||||
a: 0x00,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![5, 7],
|
||||
};
|
||||
let result = Command::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
|
@ -565,14 +667,18 @@ mod tests {
|
|||
compression,
|
||||
)
|
||||
.into();
|
||||
let Packet(header, mut payload) = p;
|
||||
|
||||
let Packet {
|
||||
header,
|
||||
mut payload,
|
||||
} = p;
|
||||
|
||||
// mangle it
|
||||
for byte in payload.iter_mut() {
|
||||
*byte -= *byte / 2;
|
||||
}
|
||||
|
||||
let p = Packet(header, payload);
|
||||
let p = Packet { header, payload };
|
||||
let result = Command::try_from(p);
|
||||
if compression != CompressionCode::Uncompressed {
|
||||
assert_eq!(result, Err(TryFromPacketError::DecompressionFailed))
|
||||
|
@ -591,14 +697,17 @@ mod tests {
|
|||
compression,
|
||||
)
|
||||
.into();
|
||||
let Packet(header, mut payload) = p;
|
||||
let Packet {
|
||||
header,
|
||||
mut payload,
|
||||
} = p;
|
||||
|
||||
// mangle it
|
||||
for byte in payload.iter_mut() {
|
||||
*byte -= *byte / 2;
|
||||
}
|
||||
|
||||
let p = Packet(header, payload);
|
||||
let p = Packet { header, payload };
|
||||
let result = Command::try_from(p);
|
||||
if compression != CompressionCode::Uncompressed {
|
||||
assert_eq!(result, Err(TryFromPacketError::DecompressionFailed))
|
||||
|
@ -612,32 +721,59 @@ mod tests {
|
|||
#[test]
|
||||
fn unexpected_payload_size_brightness() {
|
||||
assert_eq!(
|
||||
Command::try_from(Packet(
|
||||
Header(CommandCode::Brightness.into(), 0, 0, 0, 0),
|
||||
vec!(),
|
||||
)),
|
||||
Command::try_from(Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
a: 0,
|
||||
b: 0,
|
||||
c: 0,
|
||||
d: 0,
|
||||
},
|
||||
payload: vec!()
|
||||
}),
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(1, 0))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Command::try_from(Packet(
|
||||
Header(CommandCode::Brightness.into(), 0, 0, 0, 0),
|
||||
vec!(0, 0),
|
||||
)),
|
||||
Command::try_from(Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
a: 0,
|
||||
b: 0,
|
||||
c: 0,
|
||||
d: 0,
|
||||
},
|
||||
payload: vec!(0, 0)
|
||||
}),
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(1, 2))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_reserved_used() {
|
||||
let Packet(header, payload) = Command::BitmapLinear(
|
||||
let Packet { header, payload } = Command::BitmapLinear(
|
||||
0,
|
||||
BitVec::repeat(false, 8),
|
||||
CompressionCode::Uncompressed,
|
||||
)
|
||||
.into();
|
||||
let Header(command, offset, length, sub, _reserved) = header;
|
||||
let p = Packet(Header(command, offset, length, sub, 69), payload);
|
||||
let Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: sub,
|
||||
d: _reserved,
|
||||
} = header;
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: sub,
|
||||
d: 69,
|
||||
},
|
||||
payload,
|
||||
};
|
||||
assert_eq!(
|
||||
Command::try_from(p),
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
|
@ -646,14 +782,29 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn error_invalid_compression() {
|
||||
let Packet(header, payload) = Command::BitmapLinear(
|
||||
let Packet { header, payload } = Command::BitmapLinear(
|
||||
0,
|
||||
BitVec::repeat(false, 8),
|
||||
CompressionCode::Uncompressed,
|
||||
)
|
||||
.into();
|
||||
let Header(command, offset, length, _sub, reserved) = header;
|
||||
let p = Packet(Header(command, offset, length, 42, reserved), payload);
|
||||
let Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: _sub,
|
||||
d: reserved,
|
||||
} = header;
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: 42,
|
||||
d: reserved,
|
||||
},
|
||||
payload,
|
||||
};
|
||||
assert_eq!(
|
||||
Command::try_from(p),
|
||||
Err(TryFromPacketError::InvalidCompressionCode(42))
|
||||
|
@ -662,17 +813,29 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn error_unexpected_size() {
|
||||
let Packet(header, payload) = Command::BitmapLinear(
|
||||
let Packet { header, payload } = Command::BitmapLinear(
|
||||
0,
|
||||
BitVec::repeat(false, 8),
|
||||
CompressionCode::Uncompressed,
|
||||
)
|
||||
.into();
|
||||
let Header(command, offset, length, compression, reserved) = header;
|
||||
let p = Packet(
|
||||
Header(command, offset, 420, compression, reserved),
|
||||
let Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: compression,
|
||||
d: reserved,
|
||||
} = header;
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: 420,
|
||||
c: compression,
|
||||
d: reserved,
|
||||
},
|
||||
payload,
|
||||
);
|
||||
};
|
||||
assert_eq!(
|
||||
Command::try_from(p),
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(
|
||||
|
|
|
@ -9,14 +9,21 @@ use crate::Packet;
|
|||
///
|
||||
/// # Examples
|
||||
/// ```rust
|
||||
/// # use servicepoint::Command;
|
||||
/// let connection = servicepoint::Connection::open("172.23.42.29:2342")
|
||||
/// .expect("connection failed");
|
||||
/// connection.send(Command::Clear)
|
||||
/// connection.send(servicepoint::Command::Clear)
|
||||
/// .expect("send failed");
|
||||
/// ```
|
||||
pub struct Connection {
|
||||
socket: UdpSocket,
|
||||
pub enum Connection {
|
||||
/// A real connection using the UDP protocol
|
||||
Udp(UdpSocket),
|
||||
/// A fake connection for testing that does not actually send anything
|
||||
Fake,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SendError {
|
||||
IoError(std::io::Error),
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
|
@ -37,39 +44,37 @@ impl Connection {
|
|||
info!("connecting to {addr:?}");
|
||||
let socket = UdpSocket::bind("0.0.0.0:0")?;
|
||||
socket.connect(addr)?;
|
||||
Ok(Self { socket })
|
||||
Ok(Self::Udp(socket))
|
||||
}
|
||||
|
||||
/// Send something packet-like to the display. Usually this is in the form of a Command.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `packet`: the packet-like to send
|
||||
/// - `packet`: the packet-like to send
|
||||
///
|
||||
/// returns: Ok if packet was sent, otherwise socket error
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Any errors produced while sending using the underlying socket.
|
||||
/// returns: true if packet was sent, otherwise false
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
|
||||
/// # let connection = servicepoint::Connection::open("172.23.42.29:2342")
|
||||
/// # .expect("connection failed");
|
||||
/// # let connection = servicepoint::Connection::Fake;
|
||||
/// // turn off all pixels on display
|
||||
/// connection.send(Command::Clear)
|
||||
/// .expect("send failed");
|
||||
/// connection.send(servicepoint::Command::Clear)
|
||||
/// .expect("send failed");
|
||||
/// ```
|
||||
pub fn send(
|
||||
&self,
|
||||
packet: impl Into<Packet>,
|
||||
) -> Result<(), std::io::Error> {
|
||||
pub fn send(&self, packet: impl Into<Packet>) -> Result<(), SendError> {
|
||||
let packet = packet.into();
|
||||
debug!("sending {packet:?}");
|
||||
let data: Vec<u8> = packet.into();
|
||||
self.socket.send(&data)?;
|
||||
Ok(())
|
||||
match self {
|
||||
Connection::Udp(socket) => {
|
||||
socket
|
||||
.send(&data)
|
||||
.map_err(SendError::IoError)
|
||||
.map(move |_| ()) // ignore Ok value
|
||||
}
|
||||
Connection::Fake => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ pub trait Grid<T> {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `x` and `y`: position of the cell to read
|
||||
/// - `x` and `y`: position of the cell to read
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -15,7 +15,7 @@ pub trait Grid<T> {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `x` and `y`: position of the cell to read
|
||||
/// - `x` and `y`: position of the cell to read
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -26,7 +26,7 @@ pub trait Grid<T> {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `x` and `y`: position of the cell to read
|
||||
/// - `x` and `y`: position of the cell to read
|
||||
///
|
||||
/// returns: Value at position or None
|
||||
fn get_optional(&self, x: isize, y: isize) -> Option<T> {
|
||||
|
@ -41,7 +41,7 @@ pub trait Grid<T> {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `x` and `y`: position of the cell to read
|
||||
/// - `x` and `y`: position of the cell to read
|
||||
///
|
||||
/// returns: the old value or None
|
||||
fn set_optional(&mut self, x: isize, y: isize, value: T) -> bool {
|
||||
|
|
|
@ -3,25 +3,84 @@ use std::mem::size_of;
|
|||
use crate::command_code::CommandCode;
|
||||
use crate::compression::into_compressed;
|
||||
use crate::{
|
||||
Command, CompressionCode, Grid, Offset, Origin, PixelGrid, Pixels,
|
||||
Command, CompressionCode, Grid, Offset, Origin, PixelGrid, Pixels, Tiles,
|
||||
TILE_SIZE,
|
||||
};
|
||||
|
||||
/// A raw header. Should probably not be used directly.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Header(pub u16, pub u16, pub u16, pub u16, pub u16);
|
||||
/// A raw header.
|
||||
///
|
||||
/// The header specifies the kind of command, the size of the payload and where to display the
|
||||
/// payload, where applicable.
|
||||
///
|
||||
/// Because the meaning of most fields depend on the command, there are no speaking names for them.
|
||||
///
|
||||
/// Should probably only be used directly to use features not exposed by the library.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct Header {
|
||||
/// The first two bytes specify which command this packet represents.
|
||||
pub command_code: u16,
|
||||
/// First command-specific value
|
||||
pub a: u16,
|
||||
/// Second command-specific value
|
||||
pub b: u16,
|
||||
/// Third command-specific value
|
||||
pub c: u16,
|
||||
/// Fourth command-specific value
|
||||
pub d: u16,
|
||||
}
|
||||
|
||||
/// The raw payload. Should probably not be used directly.
|
||||
/// The raw payload.
|
||||
///
|
||||
/// Should probably only be used directly to use features not exposed by the library.
|
||||
pub type Payload = Vec<u8>;
|
||||
|
||||
/// The raw packet. Should probably not be used directly.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Packet(pub Header, pub Payload);
|
||||
/// The raw packet.
|
||||
///
|
||||
/// Contents should probably only be used directly to use features not exposed by the library.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Converting a packet to a command and back:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use servicepoint::{Command, Packet};
|
||||
/// # let command = Command::Clear;
|
||||
/// let packet: Packet = command.into();
|
||||
/// let command: Command = Command::try_from(packet).expect("could not read packet");
|
||||
/// ```
|
||||
///
|
||||
/// Converting a packet to bytes and back:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use servicepoint::{Command, Packet};
|
||||
/// # let command = Command::Clear;
|
||||
/// # let packet: Packet = command.into();
|
||||
/// let bytes: Vec<u8> = packet.into();
|
||||
/// let packet = Packet::try_from(bytes).expect("could not read packet from bytes");
|
||||
/// ```
|
||||
///
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Packet {
|
||||
/// Meta-information for the packed command
|
||||
pub header: Header,
|
||||
/// The data for the packed command
|
||||
pub payload: Payload,
|
||||
}
|
||||
|
||||
impl From<Packet> for Vec<u8> {
|
||||
/// Turn the packet into raw bytes ready to send
|
||||
fn from(value: Packet) -> Self {
|
||||
let Packet(Header(mode, a, b, c, d), payload) = value;
|
||||
let Packet {
|
||||
header:
|
||||
Header {
|
||||
command_code: mode,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
d,
|
||||
},
|
||||
payload,
|
||||
} = value;
|
||||
|
||||
let mut packet = vec![0u8; 10 + payload.len()];
|
||||
packet[0..=1].copy_from_slice(&u16::to_be_bytes(mode));
|
||||
|
@ -36,13 +95,6 @@ impl From<Packet> for Vec<u8> {
|
|||
}
|
||||
}
|
||||
|
||||
fn u16_from_be_slice(slice: &[u8]) -> u16 {
|
||||
let mut bytes = [0u8; 2];
|
||||
bytes[0] = slice[0];
|
||||
bytes[1] = slice[1];
|
||||
u16::from_be_bytes(bytes)
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for Packet {
|
||||
type Error = ();
|
||||
|
||||
|
@ -54,14 +106,31 @@ impl TryFrom<&[u8]> for Packet {
|
|||
return Err(());
|
||||
}
|
||||
|
||||
let mode = u16_from_be_slice(&value[0..=1]);
|
||||
let a = u16_from_be_slice(&value[2..=3]);
|
||||
let b = u16_from_be_slice(&value[4..=5]);
|
||||
let c = u16_from_be_slice(&value[6..=7]);
|
||||
let d = u16_from_be_slice(&value[8..=9]);
|
||||
let header = {
|
||||
let command_code = Self::u16_from_be_slice(&value[0..=1]);
|
||||
let a = Self::u16_from_be_slice(&value[2..=3]);
|
||||
let b = Self::u16_from_be_slice(&value[4..=5]);
|
||||
let c = Self::u16_from_be_slice(&value[6..=7]);
|
||||
let d = Self::u16_from_be_slice(&value[8..=9]);
|
||||
Header {
|
||||
command_code,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
d,
|
||||
}
|
||||
};
|
||||
let payload = value[10..].to_vec();
|
||||
|
||||
Ok(Packet(Header(mode, a, b, c, d), payload))
|
||||
Ok(Packet { header, payload })
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<u8>> for Packet {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||
Self::try_from(value.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,26 +148,23 @@ impl From<Command> for Packet {
|
|||
Command::BitmapLegacy => {
|
||||
Self::command_code_only(CommandCode::BitmapLegacy)
|
||||
}
|
||||
Command::CharBrightness(origin, grid) => Packet(
|
||||
Header(
|
||||
CommandCode::CharBrightness.into(),
|
||||
origin.x as u16,
|
||||
origin.y as u16,
|
||||
grid.width() as u16,
|
||||
grid.height() as u16,
|
||||
),
|
||||
grid.into(),
|
||||
),
|
||||
Command::Brightness(brightness) => Packet(
|
||||
Header(
|
||||
CommandCode::Brightness.into(),
|
||||
0x00000,
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x0000,
|
||||
),
|
||||
vec![brightness.into()],
|
||||
),
|
||||
Command::CharBrightness(origin, grid) => {
|
||||
Self::origin_grid_to_packet(
|
||||
origin,
|
||||
grid,
|
||||
CommandCode::CharBrightness,
|
||||
)
|
||||
}
|
||||
Command::Brightness(brightness) => Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
a: 0x00000,
|
||||
b: 0x0000,
|
||||
c: 0x0000,
|
||||
d: 0x0000,
|
||||
},
|
||||
payload: vec![brightness.into()],
|
||||
},
|
||||
Command::BitmapLinearWin(origin, pixels, compression) => {
|
||||
Self::bitmap_win_into_packet(origin, pixels, compression)
|
||||
}
|
||||
|
@ -134,15 +200,10 @@ impl From<Command> for Packet {
|
|||
bits.into(),
|
||||
)
|
||||
}
|
||||
Command::Cp437Data(origin, grid) => Packet(
|
||||
Header(
|
||||
CommandCode::Cp437Data.into(),
|
||||
origin.x as u16,
|
||||
origin.y as u16,
|
||||
grid.width() as u16,
|
||||
grid.height() as u16,
|
||||
),
|
||||
grid.into(),
|
||||
Command::Cp437Data(origin, grid) => Self::origin_grid_to_packet(
|
||||
origin,
|
||||
grid,
|
||||
CommandCode::Cp437Data,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -159,16 +220,16 @@ impl Packet {
|
|||
) -> Packet {
|
||||
let length = payload.len() as u16;
|
||||
let payload = into_compressed(compression, payload);
|
||||
Packet(
|
||||
Header(
|
||||
command.into(),
|
||||
offset as u16,
|
||||
length,
|
||||
compression.into(),
|
||||
0,
|
||||
),
|
||||
Packet {
|
||||
header: Header {
|
||||
command_code: command.into(),
|
||||
a: offset as u16,
|
||||
b: length,
|
||||
c: compression.into(),
|
||||
d: 0,
|
||||
},
|
||||
payload,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
|
@ -198,15 +259,54 @@ impl Packet {
|
|||
CompressionCode::Zstd => CommandCode::BitmapLinearWinZstd,
|
||||
};
|
||||
|
||||
Packet(
|
||||
Header(command.into(), tile_x, origin.y as u16, tile_w, pixel_h),
|
||||
Packet {
|
||||
header: Header {
|
||||
command_code: command.into(),
|
||||
a: tile_x,
|
||||
b: origin.y as u16,
|
||||
c: tile_w,
|
||||
d: pixel_h,
|
||||
},
|
||||
payload,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper method for creating empty packets only containing the command code
|
||||
fn command_code_only(code: CommandCode) -> Packet {
|
||||
Packet(Header(code.into(), 0x0000, 0x0000, 0x0000, 0x0000), vec![])
|
||||
Packet {
|
||||
header: Header {
|
||||
command_code: code.into(),
|
||||
a: 0x0000,
|
||||
b: 0x0000,
|
||||
c: 0x0000,
|
||||
d: 0x0000,
|
||||
},
|
||||
payload: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn u16_from_be_slice(slice: &[u8]) -> u16 {
|
||||
let mut bytes = [0u8; 2];
|
||||
bytes[0] = slice[0];
|
||||
bytes[1] = slice[1];
|
||||
u16::from_be_bytes(bytes)
|
||||
}
|
||||
|
||||
fn origin_grid_to_packet<T>(
|
||||
origin: Origin<Tiles>,
|
||||
grid: impl Grid<T> + Into<Payload>,
|
||||
command_code: CommandCode,
|
||||
) -> Packet {
|
||||
Packet {
|
||||
header: Header {
|
||||
command_code: command_code.into(),
|
||||
a: origin.x as u16,
|
||||
b: origin.y as u16,
|
||||
c: grid.width() as u16,
|
||||
d: grid.height() as u16,
|
||||
},
|
||||
payload: grid.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,10 +316,31 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
let p = Packet(Header(0, 1, 2, 3, 4), vec![42u8; 23]);
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: 0,
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
d: 4,
|
||||
},
|
||||
payload: vec![42u8; 23],
|
||||
};
|
||||
let data: Vec<u8> = p.into();
|
||||
let p = Packet::try_from(&*data).unwrap();
|
||||
assert_eq!(p, Packet(Header(0, 1, 2, 3, 4), vec![42u8; 23]));
|
||||
assert_eq!(
|
||||
p,
|
||||
Packet {
|
||||
header: Header {
|
||||
command_code: 0,
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
d: 4
|
||||
},
|
||||
payload: vec![42u8; 23]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -17,8 +17,8 @@ impl PixelGrid {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `width`: size in pixels in x-direction
|
||||
/// * `height`: size in pixels in y-direction
|
||||
/// - `width`: size in pixels in x-direction
|
||||
/// - `height`: size in pixels in y-direction
|
||||
///
|
||||
/// returns: `PixelGrid` initialized to all pixels off
|
||||
///
|
||||
|
@ -44,8 +44,8 @@ impl PixelGrid {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `width`: size in pixels in x-direction
|
||||
/// * `height`: size in pixels in y-direction
|
||||
/// - `width`: size in pixels in x-direction
|
||||
/// - `height`: size in pixels in y-direction
|
||||
///
|
||||
/// returns: `PixelGrid` that contains a copy of the provided data
|
||||
///
|
||||
|
@ -121,8 +121,8 @@ impl Grid<bool> for PixelGrid {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `x` and `y`: position of the cell
|
||||
/// * `value`: the value to write to the cell
|
||||
/// - `x` and `y`: position of the cell
|
||||
/// - `value`: the value to write to the cell
|
||||
///
|
||||
/// returns: old value of the cell
|
||||
///
|
||||
|
@ -143,8 +143,8 @@ impl Grid<bool> for PixelGrid {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to write to
|
||||
/// * `value`: the value to set all pixels to
|
||||
/// - `this`: instance to write to
|
||||
/// - `value`: the value to set all pixels to
|
||||
fn fill(&mut self, value: bool) {
|
||||
self.bit_vec.fill(value);
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ impl<T: PrimitiveGridType> PrimitiveGrid<T> {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `x` and `y`: position of the cell
|
||||
/// - `x` and `y`: position of the cell
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -96,7 +96,7 @@ impl<T: PrimitiveGridType> PrimitiveGrid<T> {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `x` and `y`: position of the cell
|
||||
/// - `x` and `y`: position of the cell
|
||||
///
|
||||
/// returns: Reference to cell or None
|
||||
pub fn get_ref_mut_optional(
|
||||
|
@ -117,8 +117,8 @@ impl<T: PrimitiveGridType> Grid<T> for PrimitiveGrid<T> {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `x` and `y`: position of the cell
|
||||
/// * `value`: the value to write to the cell
|
||||
/// - `x` and `y`: position of the cell
|
||||
/// - `value`: the value to write to the cell
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -132,7 +132,7 @@ impl<T: PrimitiveGridType> Grid<T> for PrimitiveGrid<T> {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `x` and `y`: position of the cell to read
|
||||
/// - `x` and `y`: position of the cell to read
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
|
|
@ -14,10 +14,10 @@ links = "servicepoint"
|
|||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = "0.26.0"
|
||||
cbindgen = "0.27.0"
|
||||
|
||||
[dependencies.servicepoint]
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
path = "../servicepoint"
|
||||
features = ["all_compressions"]
|
||||
|
||||
|
|
|
@ -17,19 +17,18 @@ This crate contains C bindings for the `servicepoint` library, enabling users to
|
|||
#include "servicepoint.h"
|
||||
|
||||
int main(void) {
|
||||
sp_Connection *connection = sp_connection_open("localhost:2342");
|
||||
SPConnection *connection = sp_connection_open("172.23.42.29:2342");
|
||||
if (connection == NULL)
|
||||
return 1;
|
||||
|
||||
sp_PixelGrid *pixels = sp_pixel_grid_new(sp_PIXEL_WIDTH, sp_PIXEL_HEIGHT);
|
||||
SPPixelGrid *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;
|
||||
SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
|
||||
while (sp_connection_send_command(connection, sp_command_clone(command)));
|
||||
|
||||
sp_connection_dealloc(connection);
|
||||
sp_command_free(command);
|
||||
sp_connection_free(connection);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
@ -53,7 +52,7 @@ You have the choice of linking statically (recommended) or dynamically.
|
|||
## Notes on differences to rust library
|
||||
|
||||
- function names are: `sp_` \<struct_name\> \<rust name\>.
|
||||
- Instances get consumed in the same way they do when writing rust / C# code. Do not use an instance after an (implicit!) free.
|
||||
- Instances get consumed in the same way they do when writing rust code. Do not use an instance after an (implicit!) free.
|
||||
- Option<T> or Result<T, E> turn into nullable return values - check for NULL!
|
||||
- There are no specifics for C++ here yet. You might get a nicer header when generating directly for C++, but it should be usable.
|
||||
- Reading and writing to instances concurrently is not safe. Only reading concurrently is safe.
|
||||
|
|
|
@ -2,6 +2,8 @@ language = "C"
|
|||
include_version = true
|
||||
cpp_compat = true
|
||||
|
||||
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
|
||||
|
||||
############################ Code Style Options ################################
|
||||
|
||||
braces = "SameLine"
|
||||
|
@ -15,22 +17,17 @@ line_endings = "LF"
|
|||
############################# Codegen Options ##################################
|
||||
|
||||
style = "both"
|
||||
sort_by = "Name"
|
||||
usize_is_size_t = true
|
||||
|
||||
[defines]
|
||||
#"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 = "sp_"
|
||||
# this is needed because otherwise the order in the C# bindings is different on different machines
|
||||
sort_by = "Name"
|
||||
|
||||
[parse]
|
||||
parse_deps = true
|
||||
include = ["servicepoint"]
|
||||
extra_bindings = ["servicepoint"]
|
||||
parse_deps = false
|
||||
|
||||
[parse.expand]
|
||||
all_features = true
|
||||
|
||||
[export]
|
||||
include = []
|
||||
exclude = []
|
||||
|
|
|
@ -6,8 +6,9 @@ REPO_ROOT := $(THIS_DIR)/../../../..
|
|||
build: out/lang_c
|
||||
|
||||
clean:
|
||||
rm -r out
|
||||
rm include/servicepoint.h
|
||||
rm -r out || true
|
||||
rm include/servicepoint.h || true
|
||||
cargo clean
|
||||
|
||||
run: out/lang_c
|
||||
out/lang_c
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,18 +2,17 @@
|
|||
#include "servicepoint.h"
|
||||
|
||||
int main(void) {
|
||||
sp_Connection *connection = sp_connection_open("localhost:2342");
|
||||
SPConnection *connection = sp_connection_open("172.23.42.29:2342");
|
||||
if (connection == NULL)
|
||||
return 1;
|
||||
|
||||
sp_PixelGrid *pixels = sp_pixel_grid_new(sp_PIXEL_WIDTH, sp_PIXEL_HEIGHT);
|
||||
SPPixelGrid *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;
|
||||
SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
|
||||
while (sp_connection_send_command(connection, sp_command_clone(command)));
|
||||
|
||||
sp_connection_dealloc(connection);
|
||||
sp_command_free(command);
|
||||
sp_connection_free(connection);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,38 +1,45 @@
|
|||
//! C functions for interacting with `BitVec`s
|
||||
//! C functions for interacting with `SPBitVec`s
|
||||
//!
|
||||
//! prefix `sp_bit_vec_`
|
||||
|
||||
use crate::c_slice::CByteSlice;
|
||||
use crate::SPByteSlice;
|
||||
use servicepoint::bitvec::prelude::{BitVec, Msb0};
|
||||
|
||||
/// cbindgen:no-export
|
||||
type SpBitVec = BitVec<u8, Msb0>;
|
||||
/// A vector of bits
|
||||
///
|
||||
/// # Examples
|
||||
/// ```C
|
||||
/// SPBitVec vec = sp_bit_vec_new(8);
|
||||
/// sp_bit_vec_set(vec, 5, true);
|
||||
/// sp_bit_vec_free(vec);
|
||||
/// ```
|
||||
pub struct SPBitVec(BitVec<u8, Msb0>);
|
||||
|
||||
/// Opaque struct needed for correct code generation.
|
||||
#[derive(Clone)]
|
||||
pub struct CBitVec {
|
||||
actual: SpBitVec,
|
||||
}
|
||||
|
||||
impl From<SpBitVec> for CBitVec {
|
||||
fn from(actual: SpBitVec) -> Self {
|
||||
Self { actual }
|
||||
impl From<BitVec<u8, Msb0>> for SPBitVec {
|
||||
fn from(actual: BitVec<u8, Msb0>) -> Self {
|
||||
Self(actual)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CBitVec> for SpBitVec {
|
||||
fn from(value: CBitVec) -> Self {
|
||||
value.actual
|
||||
impl From<SPBitVec> for BitVec<u8, Msb0> {
|
||||
fn from(value: SPBitVec) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `BitVec` instance.
|
||||
impl Clone for SPBitVec {
|
||||
fn clone(&self) -> Self {
|
||||
SPBitVec(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `SPBitVec` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `size`: size in bits.
|
||||
/// - `size`: size in bits.
|
||||
///
|
||||
/// returns: `BitVec` with all bits set to false.
|
||||
/// returns: `SPBitVec` with all bits set to false. Will never return NULL.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -43,15 +50,13 @@ impl From<CBitVec> for SpBitVec {
|
|||
/// 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_bit_vec_dealloc`.
|
||||
/// by explicitly calling `sp_bit_vec_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_bit_vec_new(size: usize) -> *mut CBitVec {
|
||||
Box::into_raw(Box::new(CBitVec {
|
||||
actual: SpBitVec::repeat(false, size),
|
||||
}))
|
||||
pub unsafe extern "C" fn sp_bit_vec_new(size: usize) -> *mut SPBitVec {
|
||||
Box::into_raw(Box::new(SPBitVec(BitVec::repeat(false, size))))
|
||||
}
|
||||
|
||||
/// Interpret the data as a series of bits and load then into a new `BitVec` instance.
|
||||
/// Interpret the data as a series of bits and load then into a new `SPBitVec` instance.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
@ -60,55 +65,53 @@ pub unsafe extern "C" fn sp_bit_vec_new(size: usize) -> *mut CBitVec {
|
|||
/// - `data` points to a valid memory location of at least `data_length`
|
||||
/// bytes in size.
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_bit_vec_dealloc`.
|
||||
/// by explicitly calling `sp_bit_vec_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_bit_vec_load(
|
||||
data: *const u8,
|
||||
data_length: usize,
|
||||
) -> *mut CBitVec {
|
||||
) -> *mut SPBitVec {
|
||||
let data = std::slice::from_raw_parts(data, data_length);
|
||||
Box::into_raw(Box::new(CBitVec {
|
||||
actual: SpBitVec::from_slice(data),
|
||||
}))
|
||||
Box::into_raw(Box::new(SPBitVec(BitVec::from_slice(data))))
|
||||
}
|
||||
|
||||
/// Clones a `BitVec`.
|
||||
/// Clones a `SPBitVec`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BitVec`
|
||||
/// - `this` is not written to concurrently
|
||||
/// - `bit_vec` points to a valid `SPBitVec`
|
||||
/// - `bit_vec` is not written to concurrently
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_bit_vec_dealloc`.
|
||||
/// by explicitly calling `sp_bit_vec_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_bit_vec_clone(
|
||||
this: *const CBitVec,
|
||||
) -> *mut CBitVec {
|
||||
Box::into_raw(Box::new((*this).clone()))
|
||||
bit_vec: *const SPBitVec,
|
||||
) -> *mut SPBitVec {
|
||||
Box::into_raw(Box::new((*bit_vec).clone()))
|
||||
}
|
||||
|
||||
/// Deallocates a `BitVec`.
|
||||
/// Deallocates a `SPBitVec`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BitVec`
|
||||
/// - `this` is not used concurrently or after this call
|
||||
/// - `this` was not passed to another consuming function, e.g. to create a `Command`
|
||||
/// - `bit_vec` points to a valid `SPBitVec`
|
||||
/// - `bit_vec` is not used concurrently or after this call
|
||||
/// - `bit_vec` was not passed to another consuming function, e.g. to create a `SPCommand`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_bit_vec_dealloc(this: *mut CBitVec) {
|
||||
_ = Box::from_raw(this);
|
||||
pub unsafe extern "C" fn sp_bit_vec_free(bit_vec: *mut SPBitVec) {
|
||||
_ = Box::from_raw(bit_vec);
|
||||
}
|
||||
|
||||
/// Gets the value of a bit from the `BitVec`.
|
||||
/// Gets the value of a bit from the `SPBitVec`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to read from
|
||||
/// * `index`: the bit index to read
|
||||
/// - `bit_vec`: instance to read from
|
||||
/// - `index`: the bit index to read
|
||||
///
|
||||
/// returns: value of the bit
|
||||
///
|
||||
|
@ -120,23 +123,23 @@ pub unsafe extern "C" fn sp_bit_vec_dealloc(this: *mut CBitVec) {
|
|||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BitVec`
|
||||
/// - `this` is not written to concurrently
|
||||
/// - `bit_vec` points to a valid `SPBitVec`
|
||||
/// - `bit_vec` is not written to concurrently
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_bit_vec_get(
|
||||
this: *const CBitVec,
|
||||
bit_vec: *const SPBitVec,
|
||||
index: usize,
|
||||
) -> bool {
|
||||
*(*this).actual.get(index).unwrap()
|
||||
*(*bit_vec).0.get(index).unwrap()
|
||||
}
|
||||
|
||||
/// Sets the value of a bit in the `BitVec`.
|
||||
/// Sets the value of a bit in the `SPBitVec`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to write to
|
||||
/// * `index`: the bit index to edit
|
||||
/// * `value`: the value to set the bit to
|
||||
/// - `bit_vec`: instance to write to
|
||||
/// - `index`: the bit index to edit
|
||||
/// - `value`: the value to set the bit to
|
||||
///
|
||||
/// returns: old value of the bit
|
||||
///
|
||||
|
@ -148,73 +151,86 @@ pub unsafe extern "C" fn sp_bit_vec_get(
|
|||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BitVec`
|
||||
/// - `this` is not written to or read from concurrently
|
||||
/// - `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_bit_vec_set(
|
||||
this: *mut CBitVec,
|
||||
bit_vec: *mut SPBitVec,
|
||||
index: usize,
|
||||
value: bool,
|
||||
) {
|
||||
(*this).actual.set(index, value)
|
||||
(*bit_vec).0.set(index, value)
|
||||
}
|
||||
|
||||
/// Sets the value of all bits in the `BitVec`.
|
||||
/// Sets the value of all bits in the `SPBitVec`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `value`: the value to set all bits to
|
||||
/// - `bit_vec`: instance to write to
|
||||
/// - `value`: the value to set all bits to
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BitVec`
|
||||
/// - `this` is not written to or read from concurrently
|
||||
/// - `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_bit_vec_fill(this: *mut CBitVec, value: bool) {
|
||||
(*this).actual.fill(value)
|
||||
pub unsafe extern "C" fn sp_bit_vec_fill(bit_vec: *mut SPBitVec, value: bool) {
|
||||
(*bit_vec).0.fill(value)
|
||||
}
|
||||
|
||||
/// Gets the length of the `BitVec` in bits.
|
||||
/// Gets the length of the `SPBitVec` in bits.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `bit_vec`: instance to write to
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BitVec`
|
||||
/// - `bit_vec` points to a valid `SPBitVec`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_bit_vec_len(this: *const CBitVec) -> usize {
|
||||
(*this).actual.len()
|
||||
pub unsafe extern "C" fn sp_bit_vec_len(bit_vec: *const SPBitVec) -> usize {
|
||||
(*bit_vec).0.len()
|
||||
}
|
||||
|
||||
/// Returns true if length is 0.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `bit_vec`: instance to write to
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BitVec`
|
||||
/// - `bit_vec` points to a valid `SPBitVec`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_bit_vec_is_empty(this: *const CBitVec) -> bool {
|
||||
(*this).actual.is_empty()
|
||||
pub unsafe extern "C" fn sp_bit_vec_is_empty(bit_vec: *const SPBitVec) -> bool {
|
||||
(*bit_vec).0.is_empty()
|
||||
}
|
||||
|
||||
/// Gets an unsafe reference to the data of the `BitVec` instance.
|
||||
/// Gets an unsafe reference to the data of the `SPBitVec` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `bit_vec`: instance to write to
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BitVec`
|
||||
/// - the returned memory range is never accessed after the passed `BitVec` has been freed
|
||||
/// - the returned memory range is never accessed concurrently, either via the `BitVec` or directly
|
||||
/// - `bit_vec` points to a valid `SPBitVec`
|
||||
/// - the returned memory range is never accessed after the passed `SPBitVec` has been freed
|
||||
/// - the returned memory range is never accessed concurrently, either via the `SPBitVec` or directly
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_bit_vec_unsafe_data_ref(
|
||||
this: *mut CBitVec,
|
||||
) -> CByteSlice {
|
||||
let data = (*this).actual.as_raw_mut_slice();
|
||||
CByteSlice {
|
||||
bit_vec: *mut SPBitVec,
|
||||
) -> SPByteSlice {
|
||||
let data = (*bit_vec).0.as_raw_mut_slice();
|
||||
SPByteSlice {
|
||||
start: data.as_mut_ptr_range().start,
|
||||
length: data.len(),
|
||||
}
|
||||
|
|
|
@ -1,37 +1,55 @@
|
|||
//! C functions for interacting with `BrightnessGrid`s
|
||||
//! C functions for interacting with `SPBrightnessGrid`s
|
||||
//!
|
||||
//! prefix `sp_brightness_grid_`
|
||||
|
||||
use servicepoint::{Brightness, BrightnessGrid, DataRef, Grid, PrimitiveGrid};
|
||||
use crate::SPByteSlice;
|
||||
use servicepoint::{Brightness, DataRef, Grid, PrimitiveGrid};
|
||||
use std::intrinsics::transmute;
|
||||
|
||||
use crate::c_slice::CByteSlice;
|
||||
|
||||
/// C-wrapper for grid containing brightness values.
|
||||
#[derive(Clone)]
|
||||
pub struct CBrightnessGrid(pub(crate) BrightnessGrid);
|
||||
|
||||
/// Creates a new `BrightnessGrid` with the specified dimensions.
|
||||
/// A grid containing brightness values.
|
||||
///
|
||||
/// returns: `BrightnessGrid` initialized to 0.
|
||||
/// # 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);
|
||||
/// ```
|
||||
pub struct SPBrightnessGrid(pub(crate) servicepoint::BrightnessGrid);
|
||||
|
||||
impl Clone for SPBrightnessGrid {
|
||||
fn clone(&self) -> Self {
|
||||
SPBrightnessGrid(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `SPBrightnessGrid` with the specified dimensions.
|
||||
///
|
||||
/// returns: `SPBrightnessGrid` initialized to 0. Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_brightness_grid_dealloc`.
|
||||
/// by explicitly calling `sp_brightness_grid_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_brightness_grid_new(
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> *mut CBrightnessGrid {
|
||||
Box::into_raw(Box::new(CBrightnessGrid(BrightnessGrid::new(
|
||||
width, height,
|
||||
))))
|
||||
) -> *mut SPBrightnessGrid {
|
||||
Box::into_raw(Box::new(SPBrightnessGrid(
|
||||
servicepoint::BrightnessGrid::new(width, height),
|
||||
)))
|
||||
}
|
||||
|
||||
/// Loads a `BrightnessGrid` with the specified dimensions from the provided data.
|
||||
/// Loads a `SPBrightnessGrid` with the specified dimensions from the provided data.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -44,60 +62,68 @@ pub unsafe extern "C" fn sp_brightness_grid_new(
|
|||
/// - `data` points to a valid memory location of at least `data_length`
|
||||
/// bytes in size.
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_brightness_grid_dealloc`.
|
||||
/// by explicitly calling `sp_brightness_grid_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_brightness_grid_load(
|
||||
width: usize,
|
||||
height: usize,
|
||||
data: *const u8,
|
||||
data_length: usize,
|
||||
) -> *mut CBrightnessGrid {
|
||||
) -> *mut SPBrightnessGrid {
|
||||
let data = std::slice::from_raw_parts(data, data_length);
|
||||
let grid = PrimitiveGrid::load(width, height, data);
|
||||
let grid =
|
||||
BrightnessGrid::try_from(grid).expect("invalid brightness value");
|
||||
Box::into_raw(Box::new(CBrightnessGrid(grid)))
|
||||
let grid = servicepoint::BrightnessGrid::try_from(grid)
|
||||
.expect("invalid brightness value");
|
||||
Box::into_raw(Box::new(SPBrightnessGrid(grid)))
|
||||
}
|
||||
|
||||
/// Clones a `BrightnessGrid`.
|
||||
/// Clones a `SPBrightnessGrid`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `brightness_grid`: instance to read from
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BrightnessGrid`
|
||||
/// - `this` is not written to concurrently
|
||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
||||
/// - `brightness_grid` is not written to concurrently
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_brightness_grid_dealloc`.
|
||||
/// by explicitly calling `sp_brightness_grid_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_brightness_grid_clone(
|
||||
this: *const CBrightnessGrid,
|
||||
) -> *mut CBrightnessGrid {
|
||||
Box::into_raw(Box::new((*this).clone()))
|
||||
brightness_grid: *const SPBrightnessGrid,
|
||||
) -> *mut SPBrightnessGrid {
|
||||
Box::into_raw(Box::new((*brightness_grid).clone()))
|
||||
}
|
||||
|
||||
/// Deallocates a `BrightnessGrid`.
|
||||
/// Deallocates a `SPBrightnessGrid`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `brightness_grid`: instance to read from
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BrightnessGrid`
|
||||
/// - `this` is not used concurrently or after this call
|
||||
/// - `this` was not passed to another consuming function, e.g. to create a `Command`
|
||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
||||
/// - `brightness_grid` is not used concurrently or after this call
|
||||
/// - `brightness_grid` was not passed to another consuming function, e.g. to create a `SPCommand`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_brightness_grid_dealloc(
|
||||
this: *mut CBrightnessGrid,
|
||||
pub unsafe extern "C" fn sp_brightness_grid_free(
|
||||
brightness_grid: *mut SPBrightnessGrid,
|
||||
) {
|
||||
_ = Box::from_raw(this);
|
||||
_ = Box::from_raw(brightness_grid);
|
||||
}
|
||||
|
||||
/// Gets the current value at the specified position.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to read from
|
||||
/// * `x` and `y`: position of the cell to read
|
||||
/// - `brightness_grid`: instance to read from
|
||||
/// - `x` and `y`: position of the cell to read
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -107,126 +133,135 @@ pub unsafe extern "C" fn sp_brightness_grid_dealloc(
|
|||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BrightnessGrid`
|
||||
/// - `this` is not written to concurrently
|
||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
||||
/// - `brightness_grid` is not written to concurrently
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_brightness_grid_get(
|
||||
this: *const CBrightnessGrid,
|
||||
brightness_grid: *const SPBrightnessGrid,
|
||||
x: usize,
|
||||
y: usize,
|
||||
) -> u8 {
|
||||
(*this).0.get(x, y).into()
|
||||
(*brightness_grid).0.get(x, y).into()
|
||||
}
|
||||
|
||||
/// Sets the value of the specified position in the `BrightnessGrid`.
|
||||
/// Sets the value of the specified position in the `SPBrightnessGrid`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to write to
|
||||
/// * `x` and `y`: position of the cell
|
||||
/// * `value`: the value to write to the cell
|
||||
/// - `brightness_grid`: instance to write to
|
||||
/// - `x` and `y`: position of the cell
|
||||
/// - `value`: the value to write to the cell
|
||||
///
|
||||
/// returns: old value of the cell
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// When accessing `x` or `y` out of bounds.
|
||||
/// - When accessing `x` or `y` out of bounds.
|
||||
/// - When providing an invalid brightness value
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BitVec`
|
||||
/// - `this` is not written to or read from concurrently
|
||||
/// - `brightness_grid` points to a valid `SPBitVec`
|
||||
/// - `brightness_grid` is not written to or read from concurrently
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_brightness_grid_set(
|
||||
this: *mut CBrightnessGrid,
|
||||
brightness_grid: *mut SPBrightnessGrid,
|
||||
x: usize,
|
||||
y: usize,
|
||||
value: u8,
|
||||
) {
|
||||
let brightness =
|
||||
Brightness::try_from(value).expect("invalid brightness value");
|
||||
(*this).0.set(x, y, brightness);
|
||||
(*brightness_grid).0.set(x, y, brightness);
|
||||
}
|
||||
|
||||
/// Sets the value of all cells in the `BrightnessGrid`.
|
||||
/// Sets the value of all cells in the `SPBrightnessGrid`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to write to
|
||||
/// * `value`: the value to set all cells to
|
||||
/// - `brightness_grid`: instance to write to
|
||||
/// - `value`: the value to set all cells to
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - When providing an invalid brightness value
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BrightnessGrid`
|
||||
/// - `this` is not written to or read from concurrently
|
||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
||||
/// - `brightness_grid` is not written to or read from concurrently
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_brightness_grid_fill(
|
||||
this: *mut CBrightnessGrid,
|
||||
brightness_grid: *mut SPBrightnessGrid,
|
||||
value: u8,
|
||||
) {
|
||||
let brightness =
|
||||
Brightness::try_from(value).expect("invalid brightness value");
|
||||
(*this).0.fill(brightness);
|
||||
(*brightness_grid).0.fill(brightness);
|
||||
}
|
||||
|
||||
/// Gets the width of the `BrightnessGrid` instance.
|
||||
/// Gets the width of the `SPBrightnessGrid` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to read from
|
||||
/// - `brightness_grid`: instance to read from
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BrightnessGrid`
|
||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_brightness_grid_width(
|
||||
this: *const CBrightnessGrid,
|
||||
brightness_grid: *const SPBrightnessGrid,
|
||||
) -> usize {
|
||||
(*this).0.width()
|
||||
(*brightness_grid).0.width()
|
||||
}
|
||||
|
||||
/// Gets the height of the `BrightnessGrid` instance.
|
||||
/// Gets the height of the `SPBrightnessGrid` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to read from
|
||||
/// - `brightness_grid`: instance to read from
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BrightnessGrid`
|
||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_brightness_grid_height(
|
||||
this: *const CBrightnessGrid,
|
||||
brightness_grid: *const SPBrightnessGrid,
|
||||
) -> usize {
|
||||
(*this).0.height()
|
||||
(*brightness_grid).0.height()
|
||||
}
|
||||
|
||||
/// Gets an unsafe reference to the data of the `BrightnessGrid` instance.
|
||||
/// Gets an unsafe reference to the data of the `SPBrightnessGrid` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `brightness_grid`: instance to read from
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BrightnessGrid`
|
||||
/// - the returned memory range is never accessed after the passed `BrightnessGrid` has been freed
|
||||
/// - the returned memory range is never accessed concurrently, either via the `BrightnessGrid` or directly
|
||||
/// - `brightness_grid` points to a valid `SPBrightnessGrid`
|
||||
/// - the returned memory range is never accessed after the passed `SPBrightnessGrid` has been freed
|
||||
/// - the returned memory range is never accessed concurrently, either via the `SPBrightnessGrid` or directly
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref(
|
||||
this: *mut CBrightnessGrid,
|
||||
) -> CByteSlice {
|
||||
assert_eq!(std::mem::size_of::<Brightness>(), 1);
|
||||
brightness_grid: *mut SPBrightnessGrid,
|
||||
) -> SPByteSlice {
|
||||
assert_eq!(core::mem::size_of::<Brightness>(), 1);
|
||||
|
||||
let data = (*this).0.data_ref_mut();
|
||||
let data = (*brightness_grid).0.data_ref_mut();
|
||||
let data: &mut [u8] = transmute(data);
|
||||
CByteSlice {
|
||||
SPByteSlice {
|
||||
start: data.as_mut_ptr_range().start,
|
||||
length: data.len(),
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#[repr(C)]
|
||||
/// Represents a span of memory (`&mut [u8]` ) as a struct usable by C code.
|
||||
///
|
||||
/// You should not create an instance of this type in your C code.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
|
@ -10,7 +12,9 @@
|
|||
/// - accesses to the memory pointed to with `start` is never accessed outside `length`
|
||||
/// - the lifetime of the `CByteSlice` does not outlive the memory it points to, as described in
|
||||
/// the function returning this type.
|
||||
pub struct CByteSlice {
|
||||
/// - an instance of this created from C is never passed to a consuming function, as the rust code
|
||||
/// will try to free the memory of a potentially separate allocator.
|
||||
pub struct SPByteSlice {
|
||||
/// The start address of the memory
|
||||
pub start: *mut u8,
|
||||
/// The amount of memory in bytes
|
|
@ -1,99 +1,137 @@
|
|||
//! C functions for interacting with `Command`s
|
||||
//! C functions for interacting with `SPCommand`s
|
||||
//!
|
||||
//! prefix `sp_command_`
|
||||
|
||||
use std::ptr::null_mut;
|
||||
|
||||
use servicepoint::{
|
||||
Brightness, Command, CompressionCode, Offset, Origin, Packet, PixelGrid,
|
||||
use servicepoint::{Brightness, Origin};
|
||||
|
||||
use crate::{
|
||||
SPBitVec, SPBrightnessGrid, SPCompressionCode, SPCp437Grid, SPPacket,
|
||||
SPPixelGrid,
|
||||
};
|
||||
|
||||
use crate::bit_vec::CBitVec;
|
||||
use crate::brightness_grid::CBrightnessGrid;
|
||||
use crate::cp437_grid::CCp437Grid;
|
||||
/// A low-level display command.
|
||||
///
|
||||
/// This struct and associated functions implement the UDP protocol for the display.
|
||||
///
|
||||
/// To send a `SPCommand`, use a `SPConnection`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```C
|
||||
/// sp_connection_send_command(connection, sp_command_clear());
|
||||
/// sp_connection_send_command(connection, sp_command_brightness(5));
|
||||
/// ```
|
||||
pub struct SPCommand(pub(crate) servicepoint::Command);
|
||||
|
||||
/// Tries to turn a `Packet` into a `Command`. The packet is deallocated in the process.
|
||||
///
|
||||
/// Returns: pointer to new `Command` instance or NULL
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `packet` points to a valid instance of `Packet`
|
||||
/// - `packet` is not used concurrently or after this call
|
||||
/// - the result is checked for NULL
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
#[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)),
|
||||
impl Clone for SPCommand {
|
||||
fn clone(&self) -> Self {
|
||||
SPCommand(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Clones a `Command` instance.
|
||||
/// Tries to turn a `SPPacket` into a `SPCommand`.
|
||||
///
|
||||
/// The packet is deallocated in the process.
|
||||
///
|
||||
/// Returns: pointer to new `SPCommand` instance or NULL
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid instance of `Command`
|
||||
/// - `this` is not written to concurrently
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - `SPPacket` points to a valid instance of `SPPacket`
|
||||
/// - `SPPacket` is not used concurrently or after this call
|
||||
/// - the result is checked for NULL
|
||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_command_try_from_packet(
|
||||
packet: *mut SPPacket,
|
||||
) -> *mut SPCommand {
|
||||
let packet = *Box::from_raw(packet);
|
||||
match servicepoint::Command::try_from(packet.0) {
|
||||
Err(_) => null_mut(),
|
||||
Ok(command) => Box::into_raw(Box::new(SPCommand(command))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Clones a `SPCommand` instance.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `command` points to a valid instance of `SPCommand`
|
||||
/// - `command` is not written to concurrently
|
||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_command_clone(
|
||||
original: *const Command,
|
||||
) -> *mut Command {
|
||||
Box::into_raw(Box::new((*original).clone()))
|
||||
command: *const SPCommand,
|
||||
) -> *mut SPCommand {
|
||||
Box::into_raw(Box::new((*command).clone()))
|
||||
}
|
||||
|
||||
/// Allocates a new `Command::Clear` instance.
|
||||
/// Set all pixels to the off state.
|
||||
///
|
||||
/// Does not affect brightness.
|
||||
///
|
||||
/// Returns: a new `Command::Clear` instance. Will never return NULL.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```C
|
||||
/// sp_connection_send_command(connection, sp_command_clear());
|
||||
/// ```
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - 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() -> *mut Command {
|
||||
Box::into_raw(Box::new(Command::Clear))
|
||||
pub unsafe extern "C" fn sp_command_clear() -> *mut SPCommand {
|
||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::Clear)))
|
||||
}
|
||||
|
||||
/// Allocates a new `Command::HardReset` instance.
|
||||
/// Kills the udp daemon on the display, which usually results in a restart.
|
||||
///
|
||||
/// Please do not send this in your normal program flow.
|
||||
///
|
||||
/// Returns: a new `Command::HardReset` instance. Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - 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() -> *mut Command {
|
||||
Box::into_raw(Box::new(Command::HardReset))
|
||||
pub unsafe extern "C" fn sp_command_hard_reset() -> *mut SPCommand {
|
||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::HardReset)))
|
||||
}
|
||||
|
||||
/// Allocates a new `Command::FadeOut` instance.
|
||||
/// A yet-to-be-tested command.
|
||||
///
|
||||
/// Returns: a new `Command::FadeOut` instance. Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - 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() -> *mut Command {
|
||||
Box::into_raw(Box::new(Command::FadeOut))
|
||||
pub unsafe extern "C" fn sp_command_fade_out() -> *mut SPCommand {
|
||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::FadeOut)))
|
||||
}
|
||||
|
||||
/// Allocates a new `Command::Brightness` instance for setting the brightness of all tiles to the
|
||||
/// same value.
|
||||
/// Set the brightness of all tiles to the same value.
|
||||
///
|
||||
/// Returns: a new `Command::Brightness` instance. Will never return NULL.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -103,201 +141,263 @@ pub unsafe extern "C" fn sp_command_fade_out() -> *mut Command {
|
|||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_command_brightness(brightness: u8) -> *mut Command {
|
||||
pub unsafe extern "C" fn sp_command_brightness(
|
||||
brightness: u8,
|
||||
) -> *mut SPCommand {
|
||||
let brightness =
|
||||
Brightness::try_from(brightness).expect("invalid brightness");
|
||||
Box::into_raw(Box::new(Command::Brightness(brightness)))
|
||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::Brightness(
|
||||
brightness,
|
||||
))))
|
||||
}
|
||||
|
||||
/// Allocates a new `Command::CharBrightness` instance.
|
||||
/// The passed `ByteGrid` gets consumed.
|
||||
/// Set the brightness of individual tiles in a rectangular area of the display.
|
||||
///
|
||||
/// The passed `SPBrightnessGrid` gets consumed.
|
||||
///
|
||||
/// Returns: a new `Command::CharBrightness` instance. Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `byte_grid` points to a valid instance of `ByteGrid`
|
||||
/// - `byte_grid` is not used concurrently or after this call
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - `grid` points to a valid instance of `SPBrightnessGrid`
|
||||
/// - `grid` is not used concurrently or after this call
|
||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_command_char_brightness(
|
||||
x: usize,
|
||||
y: usize,
|
||||
byte_grid: *mut CBrightnessGrid,
|
||||
) -> *mut Command {
|
||||
let byte_grid = *Box::from_raw(byte_grid);
|
||||
Box::into_raw(Box::new(Command::CharBrightness(
|
||||
grid: *mut SPBrightnessGrid,
|
||||
) -> *mut SPCommand {
|
||||
let byte_grid = *Box::from_raw(grid);
|
||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::CharBrightness(
|
||||
Origin::new(x, y),
|
||||
byte_grid.0,
|
||||
)))
|
||||
))))
|
||||
}
|
||||
|
||||
/// Allocates a new `Command::BitmapLinear` instance.
|
||||
/// The passed `BitVec` gets consumed.
|
||||
/// Set pixel data starting at the pixel offset on screen.
|
||||
///
|
||||
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
||||
/// once the starting row is full, overwriting will continue on column 0.
|
||||
///
|
||||
/// The contained `SPBitVec` is always uncompressed.
|
||||
///
|
||||
/// The passed `SPBitVec` gets consumed.
|
||||
///
|
||||
/// Returns: a new `Command::BitmapLinear` instance. Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `bit_vec` points to a valid instance of `BitVec`
|
||||
/// - `bit_vec` points to a valid instance of `SPBitVec`
|
||||
/// - `bit_vec` is not used concurrently or after this call
|
||||
/// - `compression` matches one of the allowed enum values
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_command_bitmap_linear(
|
||||
offset: Offset,
|
||||
bit_vec: *mut CBitVec,
|
||||
compression: CompressionCode,
|
||||
) -> *mut Command {
|
||||
offset: usize,
|
||||
bit_vec: *mut SPBitVec,
|
||||
compression: SPCompressionCode,
|
||||
) -> *mut SPCommand {
|
||||
let bit_vec = *Box::from_raw(bit_vec);
|
||||
Box::into_raw(Box::new(Command::BitmapLinear(
|
||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinear(
|
||||
offset,
|
||||
bit_vec.into(),
|
||||
compression,
|
||||
)))
|
||||
compression.try_into().expect("invalid compression code"),
|
||||
))))
|
||||
}
|
||||
|
||||
/// Allocates a new `Command::BitmapLinearAnd` instance.
|
||||
/// The passed `BitVec` gets consumed.
|
||||
/// Set pixel data according to an and-mask starting at the offset.
|
||||
///
|
||||
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
||||
/// once the starting row is full, overwriting will continue on column 0.
|
||||
///
|
||||
/// The contained `SPBitVec` is always uncompressed.
|
||||
///
|
||||
/// The passed `SPBitVec` gets consumed.
|
||||
///
|
||||
/// Returns: a new `Command::BitmapLinearAnd` instance. Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `bit_vec` points to a valid instance of `BitVec`
|
||||
/// - `bit_vec` points to a valid instance of `SPBitVec`
|
||||
/// - `bit_vec` is not used concurrently or after this call
|
||||
/// - `compression` matches one of the allowed enum values
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_command_bitmap_linear_and(
|
||||
offset: Offset,
|
||||
bit_vec: *mut CBitVec,
|
||||
compression: CompressionCode,
|
||||
) -> *mut Command {
|
||||
offset: usize,
|
||||
bit_vec: *mut SPBitVec,
|
||||
compression: SPCompressionCode,
|
||||
) -> *mut SPCommand {
|
||||
let bit_vec = *Box::from_raw(bit_vec);
|
||||
Box::into_raw(Box::new(Command::BitmapLinearAnd(
|
||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearAnd(
|
||||
offset,
|
||||
bit_vec.into(),
|
||||
compression,
|
||||
)))
|
||||
compression.try_into().expect("invalid compression code"),
|
||||
))))
|
||||
}
|
||||
|
||||
/// Allocates a new `Command::BitmapLinearOr` instance.
|
||||
/// The passed `BitVec` gets consumed.
|
||||
/// Set pixel data according to an or-mask starting at the offset.
|
||||
///
|
||||
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
||||
/// once the starting row is full, overwriting will continue on column 0.
|
||||
///
|
||||
/// The contained `SPBitVec` is always uncompressed.
|
||||
///
|
||||
/// The passed `SPBitVec` gets consumed.
|
||||
///
|
||||
/// Returns: a new `Command::BitmapLinearOr` instance. Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `bit_vec` points to a valid instance of `BitVec`
|
||||
/// - `bit_vec` points to a valid instance of `SPBitVec`
|
||||
/// - `bit_vec` is not used concurrently or after this call
|
||||
/// - `compression` matches one of the allowed enum values
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_command_bitmap_linear_or(
|
||||
offset: Offset,
|
||||
bit_vec: *mut CBitVec,
|
||||
compression: CompressionCode,
|
||||
) -> *mut Command {
|
||||
offset: usize,
|
||||
bit_vec: *mut SPBitVec,
|
||||
compression: SPCompressionCode,
|
||||
) -> *mut SPCommand {
|
||||
let bit_vec = *Box::from_raw(bit_vec);
|
||||
Box::into_raw(Box::new(Command::BitmapLinearOr(
|
||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearOr(
|
||||
offset,
|
||||
bit_vec.into(),
|
||||
compression,
|
||||
)))
|
||||
compression.try_into().expect("invalid compression code"),
|
||||
))))
|
||||
}
|
||||
|
||||
/// Allocates a new `Command::BitmapLinearXor` instance.
|
||||
/// The passed `BitVec` gets consumed.
|
||||
/// Set pixel data according to a xor-mask starting at the offset.
|
||||
///
|
||||
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
|
||||
/// once the starting row is full, overwriting will continue on column 0.
|
||||
///
|
||||
/// The contained `SPBitVec` is always uncompressed.
|
||||
///
|
||||
/// The passed `SPBitVec` gets consumed.
|
||||
///
|
||||
/// Returns: a new `Command::BitmapLinearXor` instance. Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `bit_vec` points to a valid instance of `BitVec`
|
||||
/// - `bit_vec` points to a valid instance of `SPBitVec`
|
||||
/// - `bit_vec` is not used concurrently or after this call
|
||||
/// - `compression` matches one of the allowed enum values
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
|
||||
offset: Offset,
|
||||
bit_vec: *mut CBitVec,
|
||||
compression: CompressionCode,
|
||||
) -> *mut Command {
|
||||
offset: usize,
|
||||
bit_vec: *mut SPBitVec,
|
||||
compression: SPCompressionCode,
|
||||
) -> *mut SPCommand {
|
||||
let bit_vec = *Box::from_raw(bit_vec);
|
||||
Box::into_raw(Box::new(Command::BitmapLinearXor(
|
||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearXor(
|
||||
offset,
|
||||
bit_vec.into(),
|
||||
compression,
|
||||
)))
|
||||
compression.try_into().expect("invalid compression code"),
|
||||
))))
|
||||
}
|
||||
|
||||
/// Allocates a new `Command::Cp437Data` instance.
|
||||
/// The passed `ByteGrid` gets consumed.
|
||||
/// Show text on the screen.
|
||||
///
|
||||
/// <div class="warning">
|
||||
/// The library does not currently convert between UTF-8 and CP-437.
|
||||
/// Because Rust expects UTF-8 strings, it might be necessary to only send ASCII for now.
|
||||
/// </div>
|
||||
///
|
||||
/// The passed `SPCp437Grid` gets consumed.///
|
||||
///
|
||||
/// Returns: a new `Command::Cp437Data` instance. Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `byte_grid` points to a valid instance of `ByteGrid`
|
||||
/// - `byte_grid` is not used concurrently or after this call
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - `grid` points to a valid instance of `SPCp437Grid`
|
||||
/// - `grid` is not used concurrently or after this call
|
||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_command_cp437_data(
|
||||
x: usize,
|
||||
y: usize,
|
||||
byte_grid: *mut CCp437Grid,
|
||||
) -> *mut Command {
|
||||
let byte_grid = *Box::from_raw(byte_grid);
|
||||
Box::into_raw(Box::new(Command::Cp437Data(Origin::new(x, y), byte_grid.0)))
|
||||
grid: *mut SPCp437Grid,
|
||||
) -> *mut SPCommand {
|
||||
let grid = *Box::from_raw(grid);
|
||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::Cp437Data(
|
||||
Origin::new(x, y),
|
||||
grid.0,
|
||||
))))
|
||||
}
|
||||
|
||||
/// Allocates a new `Command::BitmapLinearWin` instance.
|
||||
/// The passed `PixelGrid` gets consumed.
|
||||
/// Sets a window of pixels to the specified values.
|
||||
///
|
||||
/// The passed `SPPixelGrid` gets consumed.
|
||||
///
|
||||
/// Returns: a new `Command::BitmapLinearWin` instance. Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `pixel_grid` points to a valid instance of `PixelGrid`
|
||||
/// - `pixel_grid` points to a valid instance of `SPPixelGrid`
|
||||
/// - `pixel_grid` is not used concurrently or after this call
|
||||
/// - `compression` matches one of the allowed enum values
|
||||
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_dealloc`.
|
||||
/// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_command_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_command_bitmap_linear_win(
|
||||
x: usize,
|
||||
y: usize,
|
||||
pixel_grid: *mut PixelGrid,
|
||||
compression_code: CompressionCode,
|
||||
) -> *mut Command {
|
||||
let byte_grid = *Box::from_raw(pixel_grid);
|
||||
Box::into_raw(Box::new(Command::BitmapLinearWin(
|
||||
pixel_grid: *mut SPPixelGrid,
|
||||
compression_code: SPCompressionCode,
|
||||
) -> *mut SPCommand {
|
||||
let byte_grid = (*Box::from_raw(pixel_grid)).0;
|
||||
Box::into_raw(Box::new(SPCommand(servicepoint::Command::BitmapLinearWin(
|
||||
Origin::new(x, y),
|
||||
byte_grid,
|
||||
compression_code,
|
||||
)))
|
||||
compression_code
|
||||
.try_into()
|
||||
.expect("invalid compression code"),
|
||||
))))
|
||||
}
|
||||
|
||||
/// Deallocates a `Command`.
|
||||
/// Deallocates a `SPCommand`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```C
|
||||
/// SPCommand c = sp_command_clear();
|
||||
/// sp_command_free(c);
|
||||
/// ```
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `Command`
|
||||
/// - `this` is not used concurrently or after this call
|
||||
/// - `this` was not passed to another consuming function, e.g. to create a `Packet`
|
||||
/// - `command` points to a valid `SPCommand`
|
||||
/// - `command` is not used concurrently or after this call
|
||||
/// - `command` was not passed to another consuming function, e.g. to create a `SPPacket`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_command_dealloc(ptr: *mut Command) {
|
||||
_ = Box::from_raw(ptr);
|
||||
pub unsafe extern "C" fn sp_command_free(command: *mut SPCommand) {
|
||||
_ = Box::from_raw(command);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,24 @@
|
|||
//! C functions for interacting with `Connection`s
|
||||
//! C functions for interacting with `SPConnection`s
|
||||
//!
|
||||
//! prefix `sp_connection_`
|
||||
|
||||
use std::ffi::{c_char, CStr};
|
||||
use std::ptr::null_mut;
|
||||
|
||||
use servicepoint::{Connection, Packet};
|
||||
use crate::{SPCommand, SPPacket};
|
||||
|
||||
/// Creates a new instance of `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());
|
||||
/// ```
|
||||
pub struct SPConnection(pub(crate) servicepoint::Connection);
|
||||
|
||||
/// Creates a new instance of `SPConnection`.
|
||||
///
|
||||
/// returns: NULL if connection fails, or connected instance
|
||||
///
|
||||
|
@ -20,22 +31,23 @@ use servicepoint::{Connection, Packet};
|
|||
/// 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_dealloc`.
|
||||
/// by explicitly calling `sp_connection_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_connection_open(
|
||||
host: *const c_char,
|
||||
) -> *mut Connection {
|
||||
) -> *mut SPConnection {
|
||||
let host = CStr::from_ptr(host).to_str().expect("Bad encoding");
|
||||
let connection = match Connection::open(host) {
|
||||
let connection = match servicepoint::Connection::open(host) {
|
||||
Err(_) => return null_mut(),
|
||||
Ok(value) => value,
|
||||
};
|
||||
|
||||
Box::into_raw(Box::new(connection))
|
||||
Box::into_raw(Box::new(SPConnection(connection)))
|
||||
}
|
||||
|
||||
/// Sends a `Packet` to the display using the `Connection`.
|
||||
/// The passed `Packet` gets consumed.
|
||||
/// Sends a `SPPacket` to the display using the `SPConnection`.
|
||||
///
|
||||
/// The passed `packet` gets consumed.
|
||||
///
|
||||
/// returns: true in case of success
|
||||
///
|
||||
|
@ -43,27 +55,49 @@ pub unsafe extern "C" fn sp_connection_open(
|
|||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `connection` points to a valid instance of `Connection`
|
||||
/// - `packet` points to a valid instance of `Packet`
|
||||
/// - `connection` points to a valid instance of `SPConnection`
|
||||
/// - `packet` points to a valid instance of `SPPacket`
|
||||
/// - `packet` is not used concurrently or after this call
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_connection_send(
|
||||
connection: *const Connection,
|
||||
packet: *mut Packet,
|
||||
pub unsafe extern "C" fn sp_connection_send_packet(
|
||||
connection: *const SPConnection,
|
||||
packet: *mut SPPacket,
|
||||
) -> bool {
|
||||
let packet = Box::from_raw(packet);
|
||||
(*connection).send(*packet).is_ok()
|
||||
(*connection).0.send((*packet).0).is_ok()
|
||||
}
|
||||
|
||||
/// Closes and deallocates a `Connection`.
|
||||
/// Sends a `SPCommand` to the display using the `SPConnection`.
|
||||
///
|
||||
/// The passed `command` gets consumed.
|
||||
///
|
||||
/// returns: true in case of success
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `Connection`
|
||||
/// - `this` is not used concurrently or after this call
|
||||
/// - `connection` points to a valid instance of `SPConnection`
|
||||
/// - `command` points to a valid instance of `SPPacket`
|
||||
/// - `command` is not used concurrently or after this call
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_connection_dealloc(ptr: *mut Connection) {
|
||||
_ = Box::from_raw(ptr);
|
||||
pub unsafe extern "C" fn sp_connection_send_command(
|
||||
connection: *const SPConnection,
|
||||
command: *mut SPCommand,
|
||||
) -> bool {
|
||||
let command = (*Box::from_raw(command)).0;
|
||||
(*connection).0.send(command).is_ok()
|
||||
}
|
||||
|
||||
/// Closes and deallocates a `SPConnection`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `connection` points to a valid `SPConnection`
|
||||
/// - `connection` is not used concurrently or after this call
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_connection_free(connection: *mut SPConnection) {
|
||||
_ = Box::from_raw(connection);
|
||||
}
|
||||
|
|
48
crates/servicepoint_binding_c/src/constants.rs
Normal file
48
crates/servicepoint_binding_c/src/constants.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
//! re-exported constants for use in C
|
||||
|
||||
use servicepoint::CompressionCode;
|
||||
use std::time::Duration;
|
||||
|
||||
/// size of a single tile in one dimension
|
||||
pub const SP_TILE_SIZE: usize = 8;
|
||||
|
||||
/// Display tile count in the x-direction
|
||||
pub const SP_TILE_WIDTH: usize = 56;
|
||||
|
||||
/// Display tile count in the y-direction
|
||||
pub const SP_TILE_HEIGHT: usize = 20;
|
||||
|
||||
/// Display width in pixels
|
||||
pub const SP_PIXEL_WIDTH: usize = SP_TILE_WIDTH * SP_TILE_SIZE;
|
||||
|
||||
/// Display height in pixels
|
||||
pub const SP_PIXEL_HEIGHT: usize = SP_TILE_HEIGHT * SP_TILE_SIZE;
|
||||
|
||||
/// pixel count on whole screen
|
||||
pub const SP_PIXEL_COUNT: usize = SP_PIXEL_WIDTH * SP_PIXEL_HEIGHT;
|
||||
|
||||
/// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets.
|
||||
pub const SP_FRAME_PACING_MS: u128 = Duration::from_millis(30).as_millis();
|
||||
|
||||
/// Specifies the kind of compression to use.
|
||||
#[repr(u16)]
|
||||
pub enum SPCompressionCode {
|
||||
/// no compression
|
||||
Uncompressed = 0x0,
|
||||
/// compress using flate2 with zlib header
|
||||
Zlib = 0x677a,
|
||||
/// compress using bzip2
|
||||
Bzip2 = 0x627a,
|
||||
/// compress using lzma
|
||||
Lzma = 0x6c7a,
|
||||
/// compress using Zstandard
|
||||
Zstd = 0x7a73,
|
||||
}
|
||||
|
||||
impl TryFrom<SPCompressionCode> for CompressionCode {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: SPCompressionCode) -> Result<Self, Self::Error> {
|
||||
CompressionCode::try_from(value as u16)
|
||||
}
|
||||
}
|
|
@ -1,36 +1,51 @@
|
|||
//! C functions for interacting with `Cp437Grid`s
|
||||
//! C functions for interacting with `SPCp437Grid`s
|
||||
//!
|
||||
//! prefix `sp_cp437_grid_`
|
||||
|
||||
use servicepoint::{Cp437Grid, DataRef, Grid};
|
||||
|
||||
use crate::c_slice::CByteSlice;
|
||||
use crate::SPByteSlice;
|
||||
use servicepoint::{DataRef, Grid};
|
||||
|
||||
/// A C-wrapper for grid containing codepage 437 characters.
|
||||
///
|
||||
/// The encoding is currently not enforced.
|
||||
#[derive(Clone)]
|
||||
pub struct CCp437Grid(pub(crate) Cp437Grid);
|
||||
|
||||
/// Creates a new `Cp437Grid` with the specified dimensions.
|
||||
///
|
||||
/// returns: `Cp437Grid` initialized to 0.
|
||||
/// # 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.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_cp437_grid_dealloc`.
|
||||
/// by explicitly calling `sp_cp437_grid_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_cp437_grid_new(
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> *mut CCp437Grid {
|
||||
Box::into_raw(Box::new(CCp437Grid(Cp437Grid::new(width, height))))
|
||||
) -> *mut SPCp437Grid {
|
||||
Box::into_raw(Box::new(SPCp437Grid(servicepoint::Cp437Grid::new(width, height))))
|
||||
}
|
||||
|
||||
/// Loads a `Cp437Grid` with the specified dimensions from the provided data.
|
||||
/// Loads a `SPCp437Grid` with the specified dimensions from the provided data.
|
||||
///
|
||||
/// Will never return NULL.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -43,55 +58,57 @@ pub unsafe extern "C" fn sp_cp437_grid_new(
|
|||
/// - `data` points to a valid memory location of at least `data_length`
|
||||
/// bytes in size.
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_cp437_grid_dealloc`.
|
||||
/// by explicitly calling `sp_cp437_grid_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_cp437_grid_load(
|
||||
width: usize,
|
||||
height: usize,
|
||||
data: *const u8,
|
||||
data_length: usize,
|
||||
) -> *mut CCp437Grid {
|
||||
) -> *mut SPCp437Grid {
|
||||
let data = std::slice::from_raw_parts(data, data_length);
|
||||
Box::into_raw(Box::new(CCp437Grid(Cp437Grid::load(width, height, data))))
|
||||
Box::into_raw(Box::new(SPCp437Grid(servicepoint::Cp437Grid::load(width, height, data))))
|
||||
}
|
||||
|
||||
/// Clones a `Cp437Grid`.
|
||||
/// Clones a `SPCp437Grid`.
|
||||
///
|
||||
/// Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `Cp437Grid`
|
||||
/// - `this` is not written to concurrently
|
||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
||||
/// - `cp437_grid` is not written to concurrently
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_cp437_grid_dealloc`.
|
||||
/// by explicitly calling `sp_cp437_grid_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_cp437_grid_clone(
|
||||
this: *const CCp437Grid,
|
||||
) -> *mut CCp437Grid {
|
||||
Box::into_raw(Box::new((*this).clone()))
|
||||
cp437_grid: *const SPCp437Grid,
|
||||
) -> *mut SPCp437Grid {
|
||||
Box::into_raw(Box::new((*cp437_grid).clone()))
|
||||
}
|
||||
|
||||
/// Deallocates a `Cp437Grid`.
|
||||
/// Deallocates a `SPCp437Grid`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `Cp437Grid`
|
||||
/// - `this` is not used concurrently or after this call
|
||||
/// - `this` was not passed to another consuming function, e.g. to create a `Command`
|
||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
||||
/// - `cp437_grid` is not used concurrently or after cp437_grid call
|
||||
/// - `cp437_grid` was not passed to another consuming function, e.g. to create a `SPCommand`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_cp437_grid_dealloc(this: *mut CCp437Grid) {
|
||||
_ = Box::from_raw(this);
|
||||
pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) {
|
||||
_ = Box::from_raw(cp437_grid);
|
||||
}
|
||||
|
||||
/// Gets the current value at the specified position.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to read from
|
||||
/// * `x` and `y`: position of the cell to read
|
||||
/// - `cp437_grid`: instance to read from
|
||||
/// - `x` and `y`: position of the cell to read
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -101,24 +118,24 @@ pub unsafe extern "C" fn sp_cp437_grid_dealloc(this: *mut CCp437Grid) {
|
|||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `Cp437Grid`
|
||||
/// - `this` is not written to concurrently
|
||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
||||
/// - `cp437_grid` is not written to concurrently
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_cp437_grid_get(
|
||||
this: *const CCp437Grid,
|
||||
cp437_grid: *const SPCp437Grid,
|
||||
x: usize,
|
||||
y: usize,
|
||||
) -> u8 {
|
||||
(*this).0.get(x, y)
|
||||
(*cp437_grid).0.get(x, y)
|
||||
}
|
||||
|
||||
/// Sets the value of the specified position in the `Cp437Grid`.
|
||||
/// Sets the value of the specified position in the `SPCp437Grid`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to write to
|
||||
/// * `x` and `y`: position of the cell
|
||||
/// * `value`: the value to write to the cell
|
||||
/// - `cp437_grid`: instance to write to
|
||||
/// - `x` and `y`: position of the cell
|
||||
/// - `value`: the value to write to the cell
|
||||
///
|
||||
/// returns: old value of the cell
|
||||
///
|
||||
|
@ -130,85 +147,92 @@ pub unsafe extern "C" fn sp_cp437_grid_get(
|
|||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `BitVec`
|
||||
/// - `this` is not written to or read from concurrently
|
||||
/// - `cp437_grid` points to a valid `SPBitVec`
|
||||
/// - `cp437_grid` is not written to or read from concurrently
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_cp437_grid_set(
|
||||
this: *mut CCp437Grid,
|
||||
cp437_grid: *mut SPCp437Grid,
|
||||
x: usize,
|
||||
y: usize,
|
||||
value: u8,
|
||||
) {
|
||||
(*this).0.set(x, y, value);
|
||||
(*cp437_grid).0.set(x, y, value);
|
||||
}
|
||||
|
||||
/// Sets the value of all cells in the `Cp437Grid`.
|
||||
/// Sets the value of all cells in the `SPCp437Grid`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to write to
|
||||
/// * `value`: the value to set all cells to
|
||||
/// - `cp437_grid`: instance to write to
|
||||
/// - `value`: the value to set all cells to
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `Cp437Grid`
|
||||
/// - `this` is not written to or read from concurrently
|
||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
||||
/// - `cp437_grid` is not written to or read from concurrently
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_cp437_grid_fill(this: *mut CCp437Grid, value: u8) {
|
||||
(*this).0.fill(value);
|
||||
pub unsafe extern "C" fn sp_cp437_grid_fill(
|
||||
cp437_grid: *mut SPCp437Grid,
|
||||
value: u8,
|
||||
) {
|
||||
(*cp437_grid).0.fill(value);
|
||||
}
|
||||
|
||||
/// Gets the width of the `Cp437Grid` instance.
|
||||
/// Gets the width of the `SPCp437Grid` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to read from
|
||||
/// - `cp437_grid`: instance to read from
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `Cp437Grid`
|
||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_cp437_grid_width(this: *const CCp437Grid) -> usize {
|
||||
(*this).0.width()
|
||||
pub unsafe extern "C" fn sp_cp437_grid_width(
|
||||
cp437_grid: *const SPCp437Grid,
|
||||
) -> usize {
|
||||
(*cp437_grid).0.width()
|
||||
}
|
||||
|
||||
/// Gets the height of the `Cp437Grid` instance.
|
||||
/// Gets the height of the `SPCp437Grid` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to read from
|
||||
/// - `cp437_grid`: instance to read from
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `Cp437Grid`
|
||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_cp437_grid_height(
|
||||
this: *const CCp437Grid,
|
||||
cp437_grid: *const SPCp437Grid,
|
||||
) -> usize {
|
||||
(*this).0.height()
|
||||
(*cp437_grid).0.height()
|
||||
}
|
||||
|
||||
/// Gets an unsafe reference to the data of the `Cp437Grid` instance.
|
||||
/// Gets an unsafe reference to the data of the `SPCp437Grid` instance.
|
||||
///
|
||||
/// Will never return NULL.
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `Cp437Grid`
|
||||
/// - the returned memory range is never accessed after the passed `Cp437Grid` has been freed
|
||||
/// - the returned memory range is never accessed concurrently, either via the `Cp437Grid` or directly
|
||||
/// - `cp437_grid` points to a valid `SPCp437Grid`
|
||||
/// - the returned memory range is never accessed after the passed `SPCp437Grid` has been freed
|
||||
/// - the returned memory range is never accessed concurrently, either via the `SPCp437Grid` or directly
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_cp437_grid_unsafe_data_ref(
|
||||
this: *mut CCp437Grid,
|
||||
) -> CByteSlice {
|
||||
let data = (*this).0.data_ref_mut();
|
||||
CByteSlice {
|
||||
cp437_grid: *mut SPCp437Grid,
|
||||
) -> SPByteSlice {
|
||||
let data = (*cp437_grid).0.data_ref_mut();
|
||||
SPByteSlice {
|
||||
start: data.as_mut_ptr_range().start,
|
||||
length: data.len(),
|
||||
}
|
||||
|
|
|
@ -1,27 +1,46 @@
|
|||
//! C API wrapper for the `servicepoint` crate.
|
||||
//! C API wrapper for the [servicepoint](https://docs.rs/servicepoint/latest/servicepoint/) crate.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Make sure to check out [this GitHub repo](https://github.com/arfst23/ServicePoint) as well!
|
||||
//!
|
||||
//! ```C
|
||||
//! #include <stdio.h>
|
||||
//! #include "servicepoint.h"
|
||||
//!
|
||||
//! int main(void) {
|
||||
//! SPConnection *connection = sp_connection_open("172.23.42.29:2342");
|
||||
//! if (connection == NULL)
|
||||
//! return 1;
|
||||
//!
|
||||
//! SPPixelGrid *pixels = sp_pixel_grid_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
|
||||
//! sp_pixel_grid_fill(pixels, true);
|
||||
//!
|
||||
//! SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
|
||||
//! while (sp_connection_send_command(connection, sp_command_clone(command)));
|
||||
//!
|
||||
//! sp_command_free(command);
|
||||
//! sp_connection_free(connection);
|
||||
//! return 0;
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
pub use servicepoint::{
|
||||
CompressionCode, PIXEL_COUNT, PIXEL_HEIGHT, PIXEL_WIDTH, TILE_HEIGHT,
|
||||
TILE_SIZE, TILE_WIDTH,
|
||||
};
|
||||
pub use crate::bit_vec::*;
|
||||
pub use crate::brightness_grid::*;
|
||||
pub use crate::byte_slice::*;
|
||||
pub use crate::command::*;
|
||||
pub use crate::connection::*;
|
||||
pub use crate::constants::*;
|
||||
pub use crate::cp437_grid::*;
|
||||
pub use crate::packet::*;
|
||||
pub use crate::pixel_grid::*;
|
||||
|
||||
pub use crate::c_slice::CByteSlice;
|
||||
|
||||
pub mod bit_vec;
|
||||
|
||||
pub mod brightness_grid;
|
||||
|
||||
pub mod command;
|
||||
|
||||
pub mod connection;
|
||||
|
||||
pub mod packet;
|
||||
|
||||
pub mod pixel_grid;
|
||||
|
||||
pub mod c_slice;
|
||||
|
||||
pub mod cp437_grid;
|
||||
|
||||
/// The minimum time needed for the display to refresh the screen in ms.
|
||||
pub const FRAME_PACING_MS: u32 = servicepoint::FRAME_PACING.as_millis() as u32;
|
||||
mod bit_vec;
|
||||
mod brightness_grid;
|
||||
mod byte_slice;
|
||||
mod command;
|
||||
mod connection;
|
||||
mod constants;
|
||||
mod cp437_grid;
|
||||
mod packet;
|
||||
mod pixel_grid;
|
||||
|
|
|
@ -1,32 +1,37 @@
|
|||
//! C functions for interacting with `Packet`s
|
||||
//! C functions for interacting with `SPPacket`s
|
||||
//!
|
||||
//! prefix `sp_packet_`
|
||||
|
||||
use std::ptr::null_mut;
|
||||
|
||||
use servicepoint::{Command, Packet};
|
||||
use crate::SPCommand;
|
||||
|
||||
/// Turns a `Command` into a `Packet`.
|
||||
/// The `Command` gets consumed.
|
||||
/// The raw packet
|
||||
pub struct SPPacket(pub(crate) servicepoint::Packet);
|
||||
|
||||
/// Turns a `SPCommand` into a `SPPacket`.
|
||||
/// The `SPCommand` gets consumed.
|
||||
///
|
||||
/// Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `command` points to a valid instance of `Command`
|
||||
/// - `command` is not used concurrently or after this call
|
||||
/// - the returned `Packet` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_packet_dealloc`.
|
||||
/// - `SPCommand` points to a valid instance of `SPCommand`
|
||||
/// - `SPCommand` is not used concurrently or after this call
|
||||
/// - the returned `SPPacket` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_packet_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_packet_from_command(
|
||||
command: *mut Command,
|
||||
) -> *mut Packet {
|
||||
command: *mut SPCommand,
|
||||
) -> *mut SPPacket {
|
||||
let command = *Box::from_raw(command);
|
||||
let packet = command.into();
|
||||
let packet = SPPacket(command.0.into());
|
||||
Box::into_raw(Box::new(packet))
|
||||
}
|
||||
|
||||
/// Tries to load a `Packet` from the passed array with the specified length.
|
||||
/// Tries to load a `SPPacket` from the passed array with the specified length.
|
||||
///
|
||||
/// returns: NULL in case of an error, pointer to the allocated packet otherwise
|
||||
///
|
||||
|
@ -36,29 +41,48 @@ pub unsafe extern "C" fn sp_packet_from_command(
|
|||
///
|
||||
/// - `data` points to a valid memory region of at least `length` bytes
|
||||
/// - `data` is not written to concurrently
|
||||
/// - the returned `Packet` instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_packet_dealloc`.
|
||||
/// - 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 Packet {
|
||||
) -> *mut SPPacket {
|
||||
let data = std::slice::from_raw_parts(data, length);
|
||||
match Packet::try_from(data) {
|
||||
match servicepoint::Packet::try_from(data) {
|
||||
Err(_) => null_mut(),
|
||||
Ok(packet) => Box::into_raw(Box::new(packet)),
|
||||
Ok(packet) => Box::into_raw(Box::new(SPPacket(packet))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deallocates a `Packet`.
|
||||
/// Clones a `SPPacket`.
|
||||
///
|
||||
/// Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `Packet`
|
||||
/// - `this` is not used concurrently or after this call
|
||||
/// - `packet` points to a valid `SPPacket`
|
||||
/// - `packet` is not written to concurrently
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_packet_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_packet_dealloc(this: *mut Packet) {
|
||||
_ = Box::from_raw(this)
|
||||
pub unsafe extern "C" fn sp_packet_clone(
|
||||
packet: *const SPPacket,
|
||||
) -> *mut SPPacket {
|
||||
Box::into_raw(Box::new(SPPacket((*packet).0.clone())))
|
||||
}
|
||||
|
||||
/// Deallocates a `SPPacket`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `packet` points to a valid `SPPacket`
|
||||
/// - `packet` is not used concurrently or after this call
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_packet_free(packet: *mut SPPacket) {
|
||||
_ = Box::from_raw(packet)
|
||||
}
|
||||
|
|
|
@ -1,19 +1,31 @@
|
|||
//! C functions for interacting with `PixelGrid`s
|
||||
//! C functions for interacting with `SPPixelGrid`s
|
||||
//!
|
||||
//! prefix `sp_pixel_grid_`
|
||||
|
||||
use servicepoint::{DataRef, Grid, PixelGrid};
|
||||
use servicepoint::{DataRef, Grid};
|
||||
|
||||
use crate::c_slice::CByteSlice;
|
||||
use crate::byte_slice::SPByteSlice;
|
||||
|
||||
/// Creates a new `PixelGrid` with the specified dimensions.
|
||||
/// A grid of pixels.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```C
|
||||
/// Cp437Grid grid = sp_pixel_grid_new(8, 3);
|
||||
/// sp_pixel_grid_fill(grid, true);
|
||||
/// sp_pixel_grid_set(grid, 0, 0, false);
|
||||
/// sp_pixel_grid_free(grid);
|
||||
/// ```
|
||||
pub struct SPPixelGrid(pub(crate) servicepoint::PixelGrid);
|
||||
|
||||
/// Creates a new `SPPixelGrid` with the specified dimensions.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `width`: size in pixels in x-direction
|
||||
/// * `height`: size in pixels in y-direction
|
||||
/// - `width`: size in pixels in x-direction
|
||||
/// - `height`: size in pixels in y-direction
|
||||
///
|
||||
/// returns: `PixelGrid` initialized to all pixels off
|
||||
/// returns: `SPPixelGrid` initialized to all pixels off. Will never return NULL.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -24,23 +36,25 @@ use crate::c_slice::CByteSlice;
|
|||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_pixel_grid_dealloc`.
|
||||
/// by explicitly calling `sp_pixel_grid_free`.
|
||||
#[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)))
|
||||
) -> *mut SPPixelGrid {
|
||||
Box::into_raw(Box::new(SPPixelGrid(servicepoint::PixelGrid::new(
|
||||
width, height,
|
||||
))))
|
||||
}
|
||||
|
||||
/// Loads a `PixelGrid` with the specified dimensions from the provided data.
|
||||
/// Loads a `SPPixelGrid` with the specified dimensions from the provided data.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `width`: size in pixels in x-direction
|
||||
/// * `height`: size in pixels in y-direction
|
||||
/// - `width`: size in pixels in x-direction
|
||||
/// - `height`: size in pixels in y-direction
|
||||
///
|
||||
/// returns: `PixelGrid` that contains a copy of the provided data
|
||||
/// returns: `SPPixelGrid` that contains a copy of the provided data. Will never return NULL.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -53,55 +67,59 @@ pub unsafe extern "C" fn sp_pixel_grid_new(
|
|||
///
|
||||
/// - `data` points to a valid memory location of at least `data_length` bytes in size.
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_pixel_grid_dealloc`.
|
||||
/// by explicitly calling `sp_pixel_grid_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_pixel_grid_load(
|
||||
width: usize,
|
||||
height: usize,
|
||||
data: *const u8,
|
||||
data_length: usize,
|
||||
) -> *mut PixelGrid {
|
||||
) -> *mut SPPixelGrid {
|
||||
let data = std::slice::from_raw_parts(data, data_length);
|
||||
Box::into_raw(Box::new(PixelGrid::load(width, height, data)))
|
||||
Box::into_raw(Box::new(SPPixelGrid(servicepoint::PixelGrid::load(
|
||||
width, height, data,
|
||||
))))
|
||||
}
|
||||
|
||||
/// Clones a `PixelGrid`.
|
||||
/// Clones a `SPPixelGrid`.
|
||||
///
|
||||
/// Will never return NULL.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `PixelGrid`
|
||||
/// - `this` is not written to concurrently
|
||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
||||
/// - `pixel_grid` is not written to concurrently
|
||||
/// - the returned instance is freed in some way, either by using a consuming function or
|
||||
/// by explicitly calling `sp_pixel_grid_dealloc`.
|
||||
/// by explicitly calling `sp_pixel_grid_free`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_pixel_grid_clone(
|
||||
this: *const PixelGrid,
|
||||
) -> *mut PixelGrid {
|
||||
Box::into_raw(Box::new((*this).clone()))
|
||||
pixel_grid: *const SPPixelGrid,
|
||||
) -> *mut SPPixelGrid {
|
||||
Box::into_raw(Box::new(SPPixelGrid((*pixel_grid).0.clone())))
|
||||
}
|
||||
|
||||
/// Deallocates a `PixelGrid`.
|
||||
/// Deallocates a `SPPixelGrid`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `PixelGrid`
|
||||
/// - `this` is not used concurrently or after this call
|
||||
/// - `this` was not passed to another consuming function, e.g. to create a `Command`
|
||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
||||
/// - `pixel_grid` is not used concurrently or after pixel_grid call
|
||||
/// - `pixel_grid` was not passed to another consuming function, e.g. to create a `SPCommand`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_pixel_grid_dealloc(this: *mut PixelGrid) {
|
||||
_ = Box::from_raw(this);
|
||||
pub unsafe extern "C" fn sp_pixel_grid_free(pixel_grid: *mut SPPixelGrid) {
|
||||
_ = Box::from_raw(pixel_grid);
|
||||
}
|
||||
|
||||
/// Gets the current value at the specified position in the `PixelGrid`.
|
||||
/// Gets the current value at the specified position in the `SPPixelGrid`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to read from
|
||||
/// * `x` and `y`: position of the cell to read
|
||||
/// - `pixel_grid`: instance to read from
|
||||
/// - `x` and `y`: position of the cell to read
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -111,24 +129,24 @@ pub unsafe extern "C" fn sp_pixel_grid_dealloc(this: *mut PixelGrid) {
|
|||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `PixelGrid`
|
||||
/// - `this` is not written to concurrently
|
||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
||||
/// - `pixel_grid` is not written to concurrently
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_pixel_grid_get(
|
||||
this: *const PixelGrid,
|
||||
pixel_grid: *const SPPixelGrid,
|
||||
x: usize,
|
||||
y: usize,
|
||||
) -> bool {
|
||||
(*this).get(x, y)
|
||||
(*pixel_grid).0.get(x, y)
|
||||
}
|
||||
|
||||
/// Sets the value of the specified position in the `PixelGrid`.
|
||||
/// Sets the value of the specified position in the `SPPixelGrid`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to write to
|
||||
/// * `x` and `y`: position of the cell
|
||||
/// * `value`: the value to write to the cell
|
||||
/// - `pixel_grid`: instance to write to
|
||||
/// - `x` and `y`: position of the cell
|
||||
/// - `value`: the value to write to the cell
|
||||
///
|
||||
/// returns: old value of the cell
|
||||
///
|
||||
|
@ -140,83 +158,90 @@ pub unsafe extern "C" fn sp_pixel_grid_get(
|
|||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `PixelGrid`
|
||||
/// - `this` is not written to or read from concurrently
|
||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
||||
/// - `pixel_grid` is not written to or read from concurrently
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_pixel_grid_set(
|
||||
this: *mut PixelGrid,
|
||||
pixel_grid: *mut SPPixelGrid,
|
||||
x: usize,
|
||||
y: usize,
|
||||
value: bool,
|
||||
) {
|
||||
(*this).set(x, y, value);
|
||||
(*pixel_grid).0.set(x, y, value);
|
||||
}
|
||||
|
||||
/// Sets the state of all pixels in the `PixelGrid`.
|
||||
/// Sets the state of all pixels in the `SPPixelGrid`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to write to
|
||||
/// * `value`: the value to set all pixels to
|
||||
/// - `pixel_grid`: instance to write to
|
||||
/// - `value`: the value to set all pixels to
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `PixelGrid`
|
||||
/// - `this` is not written to or read from concurrently
|
||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
||||
/// - `pixel_grid` is not written to or read from concurrently
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_pixel_grid_fill(this: *mut PixelGrid, value: bool) {
|
||||
(*this).fill(value);
|
||||
pub unsafe extern "C" fn sp_pixel_grid_fill(
|
||||
pixel_grid: *mut SPPixelGrid,
|
||||
value: bool,
|
||||
) {
|
||||
(*pixel_grid).0.fill(value);
|
||||
}
|
||||
|
||||
/// Gets the width in pixels of the `PixelGrid` instance.
|
||||
/// Gets the width in pixels of the `SPPixelGrid` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to read from
|
||||
/// - `pixel_grid`: instance to read from
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `PixelGrid`
|
||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_pixel_grid_width(this: *const PixelGrid) -> usize {
|
||||
(*this).width()
|
||||
pub unsafe extern "C" fn sp_pixel_grid_width(
|
||||
pixel_grid: *const SPPixelGrid,
|
||||
) -> usize {
|
||||
(*pixel_grid).0.width()
|
||||
}
|
||||
|
||||
/// Gets the height in pixels of the `PixelGrid` instance.
|
||||
/// Gets the height in pixels of the `SPPixelGrid` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `this`: instance to read from
|
||||
/// - `pixel_grid`: instance to read from
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `PixelGrid`
|
||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_pixel_grid_height(this: *const PixelGrid) -> usize {
|
||||
(*this).height()
|
||||
pub unsafe extern "C" fn sp_pixel_grid_height(
|
||||
pixel_grid: *const SPPixelGrid,
|
||||
) -> usize {
|
||||
(*pixel_grid).0.height()
|
||||
}
|
||||
|
||||
/// Gets an unsafe reference to the data of the `PixelGrid` instance.
|
||||
/// Gets an unsafe reference to the data of the `SPPixelGrid` instance.
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// The caller has to make sure that:
|
||||
///
|
||||
/// - `this` points to a valid `PixelGrid`
|
||||
/// - the returned memory range is never accessed after the passed `PixelGrid` has been freed
|
||||
/// - the returned memory range is never accessed concurrently, either via the `PixelGrid` or directly
|
||||
/// - `pixel_grid` points to a valid `SPPixelGrid`
|
||||
/// - the returned memory range is never accessed after the passed `SPPixelGrid` has been freed
|
||||
/// - the returned memory range is never accessed concurrently, either via the `SPPixelGrid` or directly
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp_pixel_grid_unsafe_data_ref(
|
||||
this: *mut PixelGrid,
|
||||
) -> CByteSlice {
|
||||
let data = (*this).data_ref_mut();
|
||||
CByteSlice {
|
||||
pixel_grid: *mut SPPixelGrid,
|
||||
) -> SPByteSlice {
|
||||
let data = (*pixel_grid).0.data_ref_mut();
|
||||
SPByteSlice {
|
||||
start: data.as_mut_ptr_range().start,
|
||||
length: data.len(),
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ crate-type = ["cdylib"]
|
|||
test = false
|
||||
|
||||
[build-dependencies]
|
||||
csbindgen = "1.8.0"
|
||||
csbindgen = "1.9.3"
|
||||
|
||||
[dependencies]
|
||||
servicepoint_binding_c = { version = "0.7.0", path = "../servicepoint_binding_c" }
|
||||
servicepoint = { version = "0.7.0", path = "../servicepoint" }
|
||||
servicepoint_binding_c = { version = "0.8.0", path = "../servicepoint_binding_c" }
|
||||
servicepoint = { version = "0.8.0", path = "../servicepoint" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -39,7 +39,7 @@ 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 submodule add https://github.com/cccb/servicepoint.git
|
||||
git commit -m "add servicepoint submodule"
|
||||
```
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,7 +2,7 @@ using ServicePoint.BindGen;
|
|||
|
||||
namespace ServicePoint;
|
||||
|
||||
public sealed class BitVec : SpNativeInstance<BindGen.CBitVec>
|
||||
public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
|
||||
{
|
||||
public static BitVec New(int size)
|
||||
{
|
||||
|
@ -80,12 +80,9 @@ public sealed class BitVec : SpNativeInstance<BindGen.CBitVec>
|
|||
}
|
||||
}
|
||||
|
||||
private unsafe BitVec(BindGen.CBitVec* instance) : base(instance)
|
||||
private unsafe BitVec(BindGen.BitVec* instance) : base(instance)
|
||||
{
|
||||
}
|
||||
|
||||
private protected override unsafe void Dealloc()
|
||||
{
|
||||
NativeMethods.sp_bit_vec_dealloc(Instance);
|
||||
}
|
||||
private protected override unsafe void Free() => NativeMethods.sp_bit_vec_free(Instance);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ using ServicePoint.BindGen;
|
|||
|
||||
namespace ServicePoint;
|
||||
|
||||
public sealed class BrightnessGrid : SpNativeInstance<BindGen.CBrightnessGrid>
|
||||
public sealed class BrightnessGrid : SpNativeInstance<BindGen.BrightnessGrid>
|
||||
{
|
||||
public static BrightnessGrid New(int width, int height)
|
||||
{
|
||||
|
@ -92,12 +92,9 @@ public sealed class BrightnessGrid : SpNativeInstance<BindGen.CBrightnessGrid>
|
|||
}
|
||||
}
|
||||
|
||||
private unsafe BrightnessGrid(BindGen.CBrightnessGrid* instance) : base(instance)
|
||||
private unsafe BrightnessGrid(BindGen.BrightnessGrid* instance) : base(instance)
|
||||
{
|
||||
}
|
||||
|
||||
private protected override unsafe void Dealloc()
|
||||
{
|
||||
NativeMethods.sp_brightness_grid_dealloc(Instance);
|
||||
}
|
||||
private protected override unsafe void Free() => NativeMethods.sp_brightness_grid_free(Instance);
|
||||
}
|
||||
|
|
|
@ -125,8 +125,5 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
|
|||
{
|
||||
}
|
||||
|
||||
private protected override unsafe void Dealloc()
|
||||
{
|
||||
NativeMethods.sp_command_dealloc(Instance);
|
||||
}
|
||||
private protected override unsafe void Free() => NativeMethods.sp_command_free(Instance);
|
||||
}
|
||||
|
|
|
@ -20,15 +20,20 @@ public sealed class Connection : SpNativeInstance<BindGen.Connection>
|
|||
{
|
||||
unsafe
|
||||
{
|
||||
return NativeMethods.sp_connection_send(Instance, packet.Into());
|
||||
return NativeMethods.sp_connection_send_packet(Instance, packet.Into());
|
||||
}
|
||||
}
|
||||
|
||||
private protected override unsafe void Dealloc()
|
||||
public bool Send(Command command)
|
||||
{
|
||||
NativeMethods.sp_connection_dealloc(Instance);
|
||||
unsafe
|
||||
{
|
||||
return NativeMethods.sp_connection_send_command(Instance, command.Into());
|
||||
}
|
||||
}
|
||||
|
||||
private protected override unsafe void Free() => NativeMethods.sp_connection_free(Instance);
|
||||
|
||||
private unsafe Connection(BindGen.Connection* instance) : base(instance)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ using ServicePoint.BindGen;
|
|||
|
||||
namespace ServicePoint;
|
||||
|
||||
public sealed class Cp437Grid : SpNativeInstance<BindGen.CCp437Grid>
|
||||
public sealed class Cp437Grid : SpNativeInstance<BindGen.Cp437Grid>
|
||||
{
|
||||
public static Cp437Grid New(int width, int height)
|
||||
{
|
||||
|
@ -123,12 +123,9 @@ public sealed class Cp437Grid : SpNativeInstance<BindGen.CCp437Grid>
|
|||
}
|
||||
}
|
||||
|
||||
private unsafe Cp437Grid(BindGen.CCp437Grid* instance) : base(instance)
|
||||
private unsafe Cp437Grid(BindGen.Cp437Grid* instance) : base(instance)
|
||||
{
|
||||
}
|
||||
|
||||
private protected override unsafe void Dealloc()
|
||||
{
|
||||
NativeMethods.sp_cp437_grid_dealloc(Instance);
|
||||
}
|
||||
private protected override unsafe void Free() => NativeMethods.sp_cp437_grid_free(Instance);
|
||||
}
|
||||
|
|
|
@ -32,8 +32,5 @@ public sealed class Packet : SpNativeInstance<BindGen.Packet>
|
|||
{
|
||||
}
|
||||
|
||||
private protected override unsafe void Dealloc()
|
||||
{
|
||||
NativeMethods.sp_packet_dealloc(Instance);
|
||||
}
|
||||
private protected override unsafe void Free() => NativeMethods.sp_packet_free(Instance);
|
||||
}
|
||||
|
|
|
@ -96,8 +96,5 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
|
|||
{
|
||||
}
|
||||
|
||||
private protected override unsafe void Dealloc()
|
||||
{
|
||||
NativeMethods.sp_pixel_grid_dealloc(Instance);
|
||||
}
|
||||
private protected override unsafe void Free() => NativeMethods.sp_pixel_grid_free(Instance);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<PackageId>ServicePoint</PackageId>
|
||||
<Version>0.7.0</Version>
|
||||
<Version>0.8.0</Version>
|
||||
<Authors>Repository Authors</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>ServicePoint</Product>
|
||||
|
|
|
@ -22,7 +22,7 @@ public abstract class SpNativeInstance<T>
|
|||
_instance = instance;
|
||||
}
|
||||
|
||||
private protected abstract void Dealloc();
|
||||
private protected abstract void Free();
|
||||
|
||||
internal unsafe T* Into()
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ public abstract class SpNativeInstance<T>
|
|||
private unsafe void ReleaseUnmanagedResources()
|
||||
{
|
||||
if (_instance != null)
|
||||
Dealloc();
|
||||
Free();
|
||||
_instance = null;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +1,35 @@
|
|||
//! Build script generating the C# code needed to call methods from the `servicepoint` C library.
|
||||
|
||||
use std::fs;
|
||||
|
||||
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/brightness_grid.rs")
|
||||
.input_extern_file("../servicepoint_binding_c/src/cp437_grid.rs")
|
||||
.input_extern_file("../servicepoint_binding_c/src/command.rs")
|
||||
.input_extern_file("../servicepoint_binding_c/src/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/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")
|
||||
|
||||
let mut builder = csbindgen::Builder::default();
|
||||
|
||||
for source in fs::read_dir("../servicepoint_binding_c/src").unwrap() {
|
||||
let path = source.unwrap().path();
|
||||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
builder = builder.input_extern_file(path);
|
||||
}
|
||||
|
||||
builder
|
||||
.csharp_dll_name("servicepoint_binding_c")
|
||||
.csharp_namespace("ServicePoint.BindGen")
|
||||
.csharp_use_nint_types(true)
|
||||
.csharp_class_accessibility("public")
|
||||
.csharp_generate_const_filter(|_| true)
|
||||
.csharp_type_rename(move |name| {
|
||||
if name.len() > 2
|
||||
&& name.starts_with("SP")
|
||||
&& name.chars().nth(2).unwrap().is_uppercase()
|
||||
{
|
||||
name[2..].to_string()
|
||||
} else {
|
||||
name
|
||||
}
|
||||
})
|
||||
.generate_csharp_file("ServicePoint/BindGen/ServicePoint.g.cs")
|
||||
.unwrap();
|
||||
}
|
||||
|
|
34
shell.nix
34
shell.nix
|
@ -1,16 +1,24 @@
|
|||
{pkgs ? import <nixpkgs> {}}:
|
||||
pkgs.mkShell {
|
||||
nativeBuildInputs = with pkgs.buildPackages; [
|
||||
rustc cargo gcc rustfmt clippy
|
||||
{pkgs ? import <nixpkgs> {}}: let
|
||||
rust-toolchain = pkgs.symlinkJoin {
|
||||
name = "rust-toolchain";
|
||||
paths = with pkgs; [rustc cargo rustPlatform.rustcSrc rustfmt clippy];
|
||||
};
|
||||
in
|
||||
pkgs.mkShell {
|
||||
nativeBuildInputs = with pkgs.buildPackages; [
|
||||
rust-toolchain
|
||||
|
||||
pkg-config
|
||||
xe
|
||||
lzma
|
||||
cargo-tarpaulin
|
||||
gnumake
|
||||
pkg-config
|
||||
xe
|
||||
lzma
|
||||
|
||||
# dotnet-sdk_8
|
||||
];
|
||||
cargo-tarpaulin
|
||||
|
||||
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
|
||||
}
|
||||
gcc
|
||||
gnumake
|
||||
|
||||
# dotnet-sdk_8
|
||||
];
|
||||
|
||||
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue