Merge pull request #10 from cccb/improve-binding-docs

Improve binding documentation
This commit is contained in:
Vinzenz Schroeter 2024-09-07 15:20:36 +02:00 • committed by GitHub
commit c5cb6475b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 3354 additions and 1630 deletions

1
.envrc.default Normal file
View file

@ -0,0 +1 @@
use nix

1
.gitignore vendored
View file

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

28
CONTRIBUTING.md Normal file
View 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
View file

@ -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",

View file

@ -6,7 +6,7 @@ members = [
]
[workspace.package]
version = "0.7.0"
version = "0.8.0"
[workspace.lints.rust]
missing-docs = "warn"

View file

@ -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
View 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.

View file

@ -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

View file

@ -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(

View file

@ -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(()),
}
}
}

View file

@ -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 {

View file

@ -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]

View file

@ -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);
}

View file

@ -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
///

View file

@ -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"]

View file

@ -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.

View file

@ -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 = []

View file

@ -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

View file

@ -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;
}

Some files were not shown because too many files have changed in this diff Show more