diff --git a/.envrc b/.envrc.default similarity index 100% rename from .envrc rename to .envrc.default diff --git a/.gitignore b/.gitignore index 39156e2..b5806a2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ out bin obj .direnv +.envrc diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..dfc1dcf --- /dev/null +++ b/CONTRIBUTING.md @@ -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. diff --git a/Cargo.lock b/Cargo.lock index 0feeed0..9328e45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", + "windows-sys 0.52.0", ] -[[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" +name = "toml" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ - "winapi-util", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", ] [[package]] -name = "textwrap" -version = "0.16.1" +name = "toml_datetime" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] [[package]] -name = "toml" -version = "0.5.11" +name = "toml_edit" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ + "indexmap", "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] @@ -694,50 +657,28 @@ 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" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-sys", + "windows-targets", ] -[[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" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +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" @@ -806,29 +756,50 @@ dependencies = [ "tap", ] +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +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.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" +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", diff --git a/Cargo.toml b/Cargo.toml index 47241fd..9efa925 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ ] [workspace.package] -version = "0.7.0" +version = "0.8.0" [workspace.lints.rust] missing-docs = "warn" diff --git a/README.md b/README.md index c355df0..a4e2836 100644 --- a/README.md +++ b/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 - -- 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 +## Contributing -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. diff --git a/about_display.md b/about_display.md new file mode 100644 index 0000000..4fe7911 --- /dev/null +++ b/about_display.md @@ -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. diff --git a/crates/servicepoint/README.md b/crates/servicepoint/README.md index 1aa717f..daed5f3 100644 --- a/crates/servicepoint/README.md +++ b/crates/servicepoint/README.md @@ -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 diff --git a/crates/servicepoint/src/command.rs b/crates/servicepoint/src/command.rs index 930b5b2..d799696 100644 --- a/crates/servicepoint/src/command.rs +++ b/crates/servicepoint/src/command.rs @@ -190,10 +190,15 @@ impl TryFrom for Command { /// Try to interpret the `Packet` as one containing a `Command` fn try_from(packet: Packet) -> Result { - 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 { - 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 { - 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 { - 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 { - 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 { - 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( diff --git a/crates/servicepoint/src/connection.rs b/crates/servicepoint/src/connection.rs index d18d76b..032ffeb 100644 --- a/crates/servicepoint/src/connection.rs +++ b/crates/servicepoint/src/connection.rs @@ -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 - /// - /// returns: Ok if packet was sent, otherwise socket error - /// - /// # Errors + /// - `packet`: the packet-like to send /// - /// 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, - ) -> Result<(), std::io::Error> { + pub fn send(&self, packet: impl Into) -> Result<(), SendError> { let packet = packet.into(); debug!("sending {packet:?}"); let data: Vec = 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(()), + } } } diff --git a/crates/servicepoint/src/grid.rs b/crates/servicepoint/src/grid.rs index 7e71532..cb8f5e7 100644 --- a/crates/servicepoint/src/grid.rs +++ b/crates/servicepoint/src/grid.rs @@ -4,7 +4,7 @@ pub trait Grid { /// /// # 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 { /// /// # 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 { /// /// # 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 { @@ -41,7 +41,7 @@ pub trait Grid { /// /// # 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 { diff --git a/crates/servicepoint/src/packet.rs b/crates/servicepoint/src/packet.rs index 80ce052..67c96b4 100644 --- a/crates/servicepoint/src/packet.rs +++ b/crates/servicepoint/src/packet.rs @@ -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; -/// 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 = 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 for Vec { /// 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 for 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) -} - 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> for Packet { + type Error = (); + + fn try_from(value: Vec) -> Result { + Self::try_from(value.as_slice()) } } @@ -79,26 +148,23 @@ impl From 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 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( + origin: Origin, + grid: impl Grid + Into, + 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 = 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] diff --git a/crates/servicepoint/src/pixel_grid.rs b/crates/servicepoint/src/pixel_grid.rs index 82e45d1..4b8bcc7 100644 --- a/crates/servicepoint/src/pixel_grid.rs +++ b/crates/servicepoint/src/pixel_grid.rs @@ -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 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 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); } diff --git a/crates/servicepoint/src/primitive_grid.rs b/crates/servicepoint/src/primitive_grid.rs index 578379e..d1a507e 100644 --- a/crates/servicepoint/src/primitive_grid.rs +++ b/crates/servicepoint/src/primitive_grid.rs @@ -82,7 +82,7 @@ impl PrimitiveGrid { /// /// # Arguments /// - /// * `x` and `y`: position of the cell + /// - `x` and `y`: position of the cell /// /// # Panics /// @@ -96,7 +96,7 @@ impl PrimitiveGrid { /// /// # 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 Grid for PrimitiveGrid { /// /// # 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 Grid for PrimitiveGrid { /// /// # Arguments /// - /// * `x` and `y`: position of the cell to read + /// - `x` and `y`: position of the cell to read /// /// # Panics /// diff --git a/crates/servicepoint_binding_c/Cargo.toml b/crates/servicepoint_binding_c/Cargo.toml index 16c2f81..8b3ed7c 100644 --- a/crates/servicepoint_binding_c/Cargo.toml +++ b/crates/servicepoint_binding_c/Cargo.toml @@ -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"] diff --git a/crates/servicepoint_binding_c/README.md b/crates/servicepoint_binding_c/README.md index eacd65d..16240a9 100644 --- a/crates/servicepoint_binding_c/README.md +++ b/crates/servicepoint_binding_c/README.md @@ -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_` \ \. -- 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 or Result 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. diff --git a/crates/servicepoint_binding_c/cbindgen.toml b/crates/servicepoint_binding_c/cbindgen.toml index c65f551..1114264 100644 --- a/crates/servicepoint_binding_c/cbindgen.toml +++ b/crates/servicepoint_binding_c/cbindgen.toml @@ -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 = [] diff --git a/crates/servicepoint_binding_c/examples/lang_c/Makefile b/crates/servicepoint_binding_c/examples/lang_c/Makefile index 86cf49c..6b15722 100644 --- a/crates/servicepoint_binding_c/examples/lang_c/Makefile +++ b/crates/servicepoint_binding_c/examples/lang_c/Makefile @@ -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 diff --git a/crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h b/crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h index 270bb5c..ce780ff 100644 --- a/crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h +++ b/crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h @@ -1,5 +1,7 @@ /* Generated with cbindgen:0.26.0 */ +/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ + #include #include #include @@ -9,37 +11,37 @@ /** * pixel count on whole screen */ -#define sp_PIXEL_COUNT (sp_PIXEL_WIDTH * sp_PIXEL_HEIGHT) +#define SP_PIXEL_COUNT (SP_PIXEL_WIDTH * SP_PIXEL_HEIGHT) /** - * screen height in pixels + * Display height in pixels */ -#define sp_PIXEL_HEIGHT (sp_TILE_HEIGHT * sp_TILE_SIZE) +#define SP_PIXEL_HEIGHT (SP_TILE_HEIGHT * SP_TILE_SIZE) /** - * screen width in pixels + * Display width in pixels */ -#define sp_PIXEL_WIDTH (sp_TILE_WIDTH * sp_TILE_SIZE) +#define SP_PIXEL_WIDTH (SP_TILE_WIDTH * SP_TILE_SIZE) /** - * tile count in the y-direction + * Display tile count in the y-direction */ -#define sp_TILE_HEIGHT 20 +#define SP_TILE_HEIGHT 20 /** * size of a single tile in one dimension */ -#define sp_TILE_SIZE 8 +#define SP_TILE_SIZE 8 /** - * tile count in the x-direction + * Display tile count in the x-direction */ -#define sp_TILE_WIDTH 56 +#define SP_TILE_WIDTH 56 /** - * Specifies the kind of compression to use. Availability depends on features. + * Specifies the kind of compression to use. */ -enum sp_CompressionCode +enum SPCompressionCode #ifdef __cplusplus : uint16_t #endif // __cplusplus @@ -66,56 +68,109 @@ enum sp_CompressionCode Zstd = 31347, }; #ifndef __cplusplus -typedef uint16_t sp_CompressionCode; +typedef uint16_t SPCompressionCode; #endif // __cplusplus /** - * A display brightness value, checked for correct value range + * 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); + * ``` */ -typedef struct sp_Brightness sp_Brightness; +typedef struct SPBitVec SPBitVec; /** - * Opaque struct needed for correct code generation. + * A grid containing brightness values. + * + * # Examples + * ```C + * SPConnection connection = sp_connection_open("127.0.0.1:2342"); + * if (connection == NULL) + * return 1; + * + * SPBrightnessGrid grid = sp_brightness_grid_new(2, 2); + * sp_brightness_grid_set(grid, 0, 0, 0); + * sp_brightness_grid_set(grid, 1, 1, 10); + * + * SPCommand command = sp_command_char_brightness(grid); + * sp_connection_free(connection); + * ``` */ -typedef struct sp_CBitVec sp_CBitVec; - -typedef struct sp_CBrightnessGrid sp_CBrightnessGrid; - -typedef struct sp_CCp437Grid sp_CCp437Grid; +typedef struct SPBrightnessGrid SPBrightnessGrid; /** - * A command to send to the display. + * 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)); + * ``` */ -typedef struct sp_Command sp_Command; +typedef struct SPCommand SPCommand; /** * 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()); + * ``` */ -typedef struct sp_Connection sp_Connection; - -/** - * The raw packet. Should probably not be used directly. - */ -typedef struct sp_Packet sp_Packet; +typedef struct SPConnection SPConnection; /** - * A grid of pixels stored in packed bytes. + * A C-wrapper for grid containing codepage 437 characters. + * + * The encoding is currently not enforced. + * + * # Examples + * + * ```C + * Cp437Grid grid = sp_cp437_grid_new(4, 3); + * sp_cp437_grid_fill(grid, '?'); + * sp_cp437_grid_set(grid, 0, 0, '!'); + * sp_cp437_grid_free(grid); + * ``` */ -typedef struct sp_PixelGrid sp_PixelGrid; +typedef struct SPCp437Grid SPCp437Grid; /** - * A 2D grid of bytes + * The raw packet */ -typedef struct sp_PrimitiveGrid_Brightness sp_PrimitiveGrid_Brightness; +typedef struct SPPacket SPPacket; /** - * A 2D grid of bytes + * 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); + * ``` */ -typedef struct sp_PrimitiveGrid_u8 sp_PrimitiveGrid_u8; +typedef struct SPPixelGrid SPPixelGrid; /** * 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: @@ -123,8 +178,10 @@ typedef struct sp_PrimitiveGrid_u8 sp_PrimitiveGrid_u8; * - accesses to the memory pointed to with `start` is never accessed outside `length` * - the lifetime of the `CByteSlice` does not outlive the memory it points to, as described in * the function returning this type. + * - an instance of this created from C is never passed to a consuming function, as the rust code + * will try to free the memory of a potentially separate allocator. */ -typedef struct sp_CByteSlice { +typedef struct SPByteSlice { /** * The start address of the memory */ @@ -133,83 +190,63 @@ typedef struct sp_CByteSlice { * The amount of memory in bytes */ size_t length; -} sp_CByteSlice; - -/** - * Type alias for documenting the meaning of the u16 in enum values - */ -typedef size_t sp_Offset; - -/** - * A grid containing brightness values. - */ -typedef struct sp_PrimitiveGrid_Brightness sp_BrightnessGrid; - -/** - * A grid containing codepage 437 characters. - * - * The encoding is currently not enforced. - */ -typedef struct sp_PrimitiveGrid_u8 sp_Cp437Grid; - - - - +} SPByteSlice; #ifdef __cplusplus extern "C" { #endif // __cplusplus /** - * 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`. */ -struct sp_CBitVec *sp_bit_vec_clone(const struct sp_CBitVec *this_); +struct SPBitVec *sp_bit_vec_clone(const struct SPBitVec *bit_vec); /** - * Deallocates a `BitVec`. + * Sets the value of all bits in the `SPBitVec`. + * + * # Arguments + * + * - `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 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 written to or read from concurrently */ -void sp_bit_vec_dealloc(struct sp_CBitVec *this_); +void sp_bit_vec_fill(struct SPBitVec *bit_vec, bool value); /** - * Sets the value of all bits in the `BitVec`. - * - * # Arguments - * - * * `value`: the value to set all bits to + * Deallocates a `SPBitVec`. * * # 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 used concurrently or after this call + * - `bit_vec` was not passed to another consuming function, e.g. to create a `SPCommand` */ -void sp_bit_vec_fill(struct sp_CBitVec *this_, bool value); +void sp_bit_vec_free(struct SPBitVec *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 * @@ -221,35 +258,43 @@ void sp_bit_vec_fill(struct sp_CBitVec *this_, bool value); * * 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 */ -bool sp_bit_vec_get(const struct sp_CBitVec *this_, size_t index); +bool sp_bit_vec_get(const struct SPBitVec *bit_vec, size_t index); /** * 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` */ -bool sp_bit_vec_is_empty(const struct sp_CBitVec *this_); +bool sp_bit_vec_is_empty(const struct SPBitVec *bit_vec); /** - * 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` */ -size_t sp_bit_vec_len(const struct sp_CBitVec *this_); +size_t sp_bit_vec_len(const struct SPBitVec *bit_vec); /** - * 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 * @@ -258,19 +303,19 @@ size_t sp_bit_vec_len(const struct sp_CBitVec *this_); * - `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`. */ -struct sp_CBitVec *sp_bit_vec_load(const uint8_t *data, - size_t data_length); +struct SPBitVec *sp_bit_vec_load(const uint8_t *data, + size_t data_length); /** - * Creates a new `BitVec` instance. + * 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 * @@ -281,18 +326,18 @@ struct sp_CBitVec *sp_bit_vec_load(const uint8_t *data, * 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`. */ -struct sp_CBitVec *sp_bit_vec_new(size_t size); +struct SPBitVec *sp_bit_vec_new(size_t size); /** - * 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 * @@ -304,75 +349,92 @@ struct sp_CBitVec *sp_bit_vec_new(size_t size); * * 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 */ -void sp_bit_vec_set(struct sp_CBitVec *this_, size_t index, bool value); +void sp_bit_vec_set(struct SPBitVec *bit_vec, size_t index, bool value); /** - * 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 */ -struct sp_CByteSlice sp_bit_vec_unsafe_data_ref(struct sp_CBitVec *this_); +struct SPByteSlice sp_bit_vec_unsafe_data_ref(struct SPBitVec *bit_vec); /** - * 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`. */ -struct sp_CBrightnessGrid *sp_brightness_grid_clone(const struct sp_CBrightnessGrid *this_); +struct SPBrightnessGrid *sp_brightness_grid_clone(const struct SPBrightnessGrid *brightness_grid); /** - * Deallocates a `BrightnessGrid`. + * Sets the value of all cells in the `SPBrightnessGrid`. + * + * # Arguments + * + * - `brightness_grid`: instance to write to + * - `value`: the value to set all cells to + * + * # Panics + * + * - When providing an invalid brightness value * * # 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 written to or read from concurrently */ -void sp_brightness_grid_dealloc(struct sp_CBrightnessGrid *this_); +void sp_brightness_grid_fill(struct SPBrightnessGrid *brightness_grid, + uint8_t value); /** - * Sets the value of all cells in the `BrightnessGrid`. + * Deallocates a `SPBrightnessGrid`. * * # Arguments * - * * `this`: instance to write to - * * `value`: the value to set all cells to + * - `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 or read from concurrently + * - `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` */ -void sp_brightness_grid_fill(struct sp_CBrightnessGrid *this_, uint8_t value); +void sp_brightness_grid_free(struct SPBrightnessGrid *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 * @@ -382,30 +444,30 @@ void sp_brightness_grid_fill(struct sp_CBrightnessGrid *this_, uint8_t value); * * 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 */ -uint8_t sp_brightness_grid_get(const struct sp_CBrightnessGrid *this_, +uint8_t sp_brightness_grid_get(const struct SPBrightnessGrid *brightness_grid, size_t x, size_t y); /** - * 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` */ -size_t sp_brightness_grid_height(const struct sp_CBrightnessGrid *this_); +size_t sp_brightness_grid_height(const struct SPBrightnessGrid *brightness_grid); /** - * Loads a `BrightnessGrid` with the specified dimensions from the provided data. + * Loads a `SPBrightnessGrid` with the specified dimensions from the provided data. * * # Panics * @@ -418,177 +480,218 @@ size_t sp_brightness_grid_height(const struct sp_CBrightnessGrid *this_); * - `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`. */ -struct sp_CBrightnessGrid *sp_brightness_grid_load(size_t width, - size_t height, - const uint8_t *data, - size_t data_length); +struct SPBrightnessGrid *sp_brightness_grid_load(size_t width, + size_t height, + const uint8_t *data, + size_t data_length); /** - * Creates a new `BrightnessGrid` with the specified dimensions. + * Creates a new `SPBrightnessGrid` with the specified dimensions. * - * returns: `BrightnessGrid` initialized to 0. + * 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`. */ -struct sp_CBrightnessGrid *sp_brightness_grid_new(size_t width, - size_t height); +struct SPBrightnessGrid *sp_brightness_grid_new(size_t width, + size_t height); /** - * 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 */ -void sp_brightness_grid_set(struct sp_CBrightnessGrid *this_, +void sp_brightness_grid_set(struct SPBrightnessGrid *brightness_grid, size_t x, size_t y, uint8_t value); /** - * 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 */ -struct sp_CByteSlice sp_brightness_grid_unsafe_data_ref(struct sp_CBrightnessGrid *this_); +struct SPByteSlice sp_brightness_grid_unsafe_data_ref(struct SPBrightnessGrid *brightness_grid); /** - * 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` */ -size_t sp_brightness_grid_width(const struct sp_CBrightnessGrid *this_); +size_t sp_brightness_grid_width(const struct SPBrightnessGrid *brightness_grid); /** - * 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`. */ -struct sp_Command *sp_command_bitmap_linear(sp_Offset offset, - struct sp_CBitVec *bit_vec, - sp_CompressionCode compression); +struct SPCommand *sp_command_bitmap_linear(size_t offset, + struct SPBitVec *bit_vec, + SPCompressionCode compression); /** - * 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`. */ -struct sp_Command *sp_command_bitmap_linear_and(sp_Offset offset, - struct sp_CBitVec *bit_vec, - sp_CompressionCode compression); +struct SPCommand *sp_command_bitmap_linear_and(size_t offset, + struct SPBitVec *bit_vec, + SPCompressionCode compression); /** - * 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`. */ -struct sp_Command *sp_command_bitmap_linear_or(sp_Offset offset, - struct sp_CBitVec *bit_vec, - sp_CompressionCode compression); +struct SPCommand *sp_command_bitmap_linear_or(size_t offset, + struct SPBitVec *bit_vec, + SPCompressionCode compression); /** - * 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`. */ -struct sp_Command *sp_command_bitmap_linear_win(size_t x, - size_t y, - struct sp_PixelGrid *pixel_grid, - sp_CompressionCode compression_code); +struct SPCommand *sp_command_bitmap_linear_win(size_t x, + size_t y, + struct SPPixelGrid *pixel_grid, + SPCompressionCode 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`. */ -struct sp_Command *sp_command_bitmap_linear_xor(sp_Offset offset, - struct sp_CBitVec *bit_vec, - sp_CompressionCode compression); +struct SPCommand *sp_command_bitmap_linear_xor(size_t offset, + struct SPBitVec *bit_vec, + SPCompressionCode compression); /** - * 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 * @@ -598,139 +701,175 @@ struct sp_Command *sp_command_bitmap_linear_xor(sp_Offset offset, * * 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`. */ -struct sp_Command *sp_command_brightness(uint8_t brightness); +struct SPCommand *sp_command_brightness(uint8_t 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`. */ -struct sp_Command *sp_command_char_brightness(size_t x, - size_t y, - sp_BrightnessGrid *byte_grid); +struct SPCommand *sp_command_char_brightness(size_t x, + size_t y, + struct SPBrightnessGrid *grid); /** - * 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`. */ -struct sp_Command *sp_command_clear(void); +struct SPCommand *sp_command_clear(void); /** - * Clones a `Command` instance. + * Clones a `SPCommand` instance. * * # 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`. + * - `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`. */ -struct sp_Command *sp_command_clone(const struct sp_Command *original); +struct SPCommand *sp_command_clone(const struct SPCommand *command); /** - * Allocates a new `Command::Cp437Data` instance. - * The passed `ByteGrid` gets consumed. + * Show text on the screen. + * + *
+ * 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. + *
+ * + * 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`. */ -struct sp_Command *sp_command_cp437_data(size_t x, - size_t y, - sp_Cp437Grid *byte_grid); +struct SPCommand *sp_command_cp437_data(size_t x, + size_t y, + struct SPCp437Grid *grid); /** - * Deallocates a `Command`. + * A yet-to-be-tested command. + * + * Returns: a new `Command::FadeOut` instance. Will never return NULL. * * # 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` + * - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + * by explicitly calling `sp_command_free`. */ -void sp_command_dealloc(struct sp_Command *ptr); +struct SPCommand *sp_command_fade_out(void); /** - * Allocates a new `Command::FadeOut` instance. + * Deallocates a `SPCommand`. + * + * # Examples + * + * ```C + * SPCommand c = sp_command_clear(); + * sp_command_free(c); + * ``` * * # 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`. + * - `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` */ -struct sp_Command *sp_command_fade_out(void); +void sp_command_free(struct SPCommand *command); /** - * 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`. */ -struct sp_Command *sp_command_hard_reset(void); +struct SPCommand *sp_command_hard_reset(void); /** - * Tries to turn a `Packet` into a `Command`. The packet is deallocated in the process. + * Tries to turn a `SPPacket` into a `SPCommand`. + * + * The packet is deallocated in the process. * - * Returns: pointer to new `Command` instance or NULL + * Returns: pointer to new `SPCommand` 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 + * - `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 `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`. */ -struct sp_Command *sp_command_try_from_packet(struct sp_Packet *packet); +struct SPCommand *sp_command_try_from_packet(struct SPPacket *packet); /** - * Closes and deallocates a `Connection`. + * Closes and deallocates a `SPConnection`. * * # 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 `SPConnection` + * - `connection` is not used concurrently or after this call */ -void sp_connection_dealloc(struct sp_Connection *ptr); +void sp_connection_free(struct SPConnection *connection); /** - * Creates a new instance of `Connection`. + * Creates a new instance of `SPConnection`. * * returns: NULL if connection fails, or connected instance * @@ -743,13 +882,14 @@ void sp_connection_dealloc(struct sp_Connection *ptr); * 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`. */ -struct sp_Connection *sp_connection_open(const char *host); +struct SPConnection *sp_connection_open(const char *host); /** - * Sends a `Packet` to the display using the `Connection`. - * The passed `Packet` gets consumed. + * Sends a `SPCommand` to the display using the `SPConnection`. + * + * The passed `command` gets consumed. * * returns: true in case of success * @@ -757,64 +897,84 @@ struct sp_Connection *sp_connection_open(const char *host); * * The caller has to make sure that: * - * - `connection` points to a valid instance of `Connection` - * - `packet` points to a valid instance of `Packet` - * - `packet` 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 */ -bool sp_connection_send(const struct sp_Connection *connection, - struct sp_Packet *packet); +bool sp_connection_send_command(const struct SPConnection *connection, + struct SPCommand *command); /** - * Clones a `Cp437Grid`. + * Sends a `SPPacket` to the display using the `SPConnection`. + * + * The passed `packet` gets consumed. + * + * returns: true in case of success * * # Safety * * The caller has to make sure that: * - * - `this` points to a valid `Cp437Grid` - * - `this` 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`. + * - `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 */ -struct sp_CCp437Grid *sp_cp437_grid_clone(const struct sp_CCp437Grid *this_); +bool sp_connection_send_packet(const struct SPConnection *connection, + struct SPPacket *packet); /** - * Deallocates 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 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 written to concurrently + * - the returned instance is freed in some way, either by using a consuming function or + * by explicitly calling `sp_cp437_grid_free`. */ -void sp_cp437_grid_dealloc(struct sp_CCp437Grid *this_); +struct SPCp437Grid *sp_cp437_grid_clone(const struct SPCp437Grid *cp437_grid); /** - * 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: + * + * - `cp437_grid` points to a valid `SPCp437Grid` + * - `cp437_grid` is not written to or read from concurrently + */ +void sp_cp437_grid_fill(struct SPCp437Grid *cp437_grid, uint8_t value); + +/** + * Deallocates a `SPCp437Grid`. * * # 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 used concurrently or after cp437_grid call + * - `cp437_grid` was not passed to another consuming function, e.g. to create a `SPCommand` */ -void sp_cp437_grid_fill(struct sp_CCp437Grid *this_, uint8_t value); +void sp_cp437_grid_free(struct SPCp437Grid *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 * @@ -824,30 +984,32 @@ void sp_cp437_grid_fill(struct sp_CCp437Grid *this_, uint8_t value); * * 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 */ -uint8_t sp_cp437_grid_get(const struct sp_CCp437Grid *this_, +uint8_t sp_cp437_grid_get(const struct SPCp437Grid *cp437_grid, size_t x, size_t y); /** - * 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` */ -size_t sp_cp437_grid_height(const struct sp_CCp437Grid *this_); +size_t sp_cp437_grid_height(const struct SPCp437Grid *cp437_grid); /** - * 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 * @@ -860,36 +1022,36 @@ size_t sp_cp437_grid_height(const struct sp_CCp437Grid *this_); * - `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`. */ -struct sp_CCp437Grid *sp_cp437_grid_load(size_t width, - size_t height, - const uint8_t *data, - size_t data_length); +struct SPCp437Grid *sp_cp437_grid_load(size_t width, + size_t height, + const uint8_t *data, + size_t data_length); /** - * Creates a new `Cp437Grid` with the specified dimensions. + * Creates a new `SPCp437Grid` with the specified dimensions. * - * returns: `Cp437Grid` initialized to 0. + * 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`. */ -struct sp_CCp437Grid *sp_cp437_grid_new(size_t width, - size_t height); +struct SPCp437Grid *sp_cp437_grid_new(size_t width, + size_t height); /** - * 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 * @@ -901,71 +1063,91 @@ struct sp_CCp437Grid *sp_cp437_grid_new(size_t width, * * 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 */ -void sp_cp437_grid_set(struct sp_CCp437Grid *this_, +void sp_cp437_grid_set(struct SPCp437Grid *cp437_grid, size_t x, size_t y, uint8_t value); /** - * 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 */ -struct sp_CByteSlice sp_cp437_grid_unsafe_data_ref(struct sp_CCp437Grid *this_); +struct SPByteSlice sp_cp437_grid_unsafe_data_ref(struct SPCp437Grid *cp437_grid); /** - * 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` */ -size_t sp_cp437_grid_width(const struct sp_CCp437Grid *this_); +size_t sp_cp437_grid_width(const struct SPCp437Grid *cp437_grid); /** - * 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`. */ -void sp_packet_dealloc(struct sp_Packet *this_); +struct SPPacket *sp_packet_clone(const struct SPPacket *packet); /** - * Turns a `Command` into a `Packet`. - * The `Command` gets consumed. + * Deallocates a `SPPacket`. * * # 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`. + * - `packet` points to a valid `SPPacket` + * - `packet` is not used concurrently or after this call + */ +void sp_packet_free(struct SPPacket *packet); + +/** + * Turns a `SPCommand` into a `SPPacket`. + * The `SPCommand` gets consumed. + * + * Will never return NULL. + * + * # Safety + * + * The caller has to make sure that: + * + * - `SPCommand` points to a valid instance of `SPCommand` + * - `SPCommand` is not used concurrently or after this call + * - the returned `SPPacket` instance is freed in some way, either by using a consuming function or + * by explicitly calling `sp_packet_free`. */ -struct sp_Packet *sp_packet_from_command(struct sp_Command *command); +struct SPPacket *sp_packet_from_command(struct SPCommand *command); /** - * 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 * @@ -975,63 +1157,65 @@ struct sp_Packet *sp_packet_from_command(struct sp_Command *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`. */ -struct sp_Packet *sp_packet_try_load(const uint8_t *data, - size_t length); +struct SPPacket *sp_packet_try_load(const uint8_t *data, + size_t length); /** - * 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`. */ -struct sp_PixelGrid *sp_pixel_grid_clone(const struct sp_PixelGrid *this_); +struct SPPixelGrid *sp_pixel_grid_clone(const struct SPPixelGrid *pixel_grid); /** - * Deallocates a `PixelGrid`. + * Sets the state of all pixels in the `SPPixelGrid`. + * + * # Arguments + * + * - `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 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 written to or read from concurrently */ -void sp_pixel_grid_dealloc(struct sp_PixelGrid *this_); +void sp_pixel_grid_fill(struct SPPixelGrid *pixel_grid, bool value); /** - * Sets the state of all pixels in the `PixelGrid`. - * - * # Arguments - * - * * `this`: instance to write to - * * `value`: the value to set all pixels to + * Deallocates a `SPPixelGrid`. * * # 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 used concurrently or after pixel_grid call + * - `pixel_grid` was not passed to another consuming function, e.g. to create a `SPCommand` */ -void sp_pixel_grid_fill(struct sp_PixelGrid *this_, bool value); +void sp_pixel_grid_free(struct SPPixelGrid *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 * @@ -1041,35 +1225,37 @@ void sp_pixel_grid_fill(struct sp_PixelGrid *this_, bool value); * * 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 */ -bool sp_pixel_grid_get(const struct sp_PixelGrid *this_, size_t x, size_t y); +bool sp_pixel_grid_get(const struct SPPixelGrid *pixel_grid, + size_t x, + size_t y); /** - * 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` */ -size_t sp_pixel_grid_height(const struct sp_PixelGrid *this_); +size_t sp_pixel_grid_height(const struct SPPixelGrid *pixel_grid); /** - * 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 * @@ -1082,22 +1268,22 @@ size_t sp_pixel_grid_height(const struct sp_PixelGrid *this_); * * - `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`. */ -struct sp_PixelGrid *sp_pixel_grid_load(size_t width, - size_t height, - const uint8_t *data, - size_t data_length); +struct SPPixelGrid *sp_pixel_grid_load(size_t width, + size_t height, + const uint8_t *data, + size_t data_length); /** - * Creates a new `PixelGrid` with the specified dimensions. + * 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 * @@ -1108,19 +1294,19 @@ struct sp_PixelGrid *sp_pixel_grid_load(size_t width, * 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`. */ -struct sp_PixelGrid *sp_pixel_grid_new(size_t width, - size_t height); +struct SPPixelGrid *sp_pixel_grid_new(size_t width, + size_t height); /** - * 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 * @@ -1132,41 +1318,41 @@ struct sp_PixelGrid *sp_pixel_grid_new(size_t width, * * 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 */ -void sp_pixel_grid_set(struct sp_PixelGrid *this_, +void sp_pixel_grid_set(struct SPPixelGrid *pixel_grid, size_t x, size_t y, bool value); /** - * 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 */ -struct sp_CByteSlice sp_pixel_grid_unsafe_data_ref(struct sp_PixelGrid *this_); +struct SPByteSlice sp_pixel_grid_unsafe_data_ref(struct SPPixelGrid *pixel_grid); /** - * 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` */ -size_t sp_pixel_grid_width(const struct sp_PixelGrid *this_); +size_t sp_pixel_grid_width(const struct SPPixelGrid *pixel_grid); #ifdef __cplusplus } // extern "C" diff --git a/crates/servicepoint_binding_c/examples/lang_c/src/main.c b/crates/servicepoint_binding_c/examples/lang_c/src/main.c index 3951293..5054286 100644 --- a/crates/servicepoint_binding_c/examples/lang_c/src/main.c +++ b/crates/servicepoint_binding_c/examples/lang_c/src/main.c @@ -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; } diff --git a/crates/servicepoint_binding_c/src/bit_vec.rs b/crates/servicepoint_binding_c/src/bit_vec.rs index 2592aea..d1b353c 100644 --- a/crates/servicepoint_binding_c/src/bit_vec.rs +++ b/crates/servicepoint_binding_c/src/bit_vec.rs @@ -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; +/// 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); -/// Opaque struct needed for correct code generation. -#[derive(Clone)] -pub struct CBitVec { - actual: SpBitVec, +impl From> for SPBitVec { + fn from(actual: BitVec) -> Self { + Self(actual) + } } -impl From for CBitVec { - fn from(actual: SpBitVec) -> Self { - Self { actual } +impl From for BitVec { + fn from(value: SPBitVec) -> Self { + value.0 } } -impl From for SpBitVec { - fn from(value: CBitVec) -> Self { - value.actual +impl Clone for SPBitVec { + fn clone(&self) -> Self { + SPBitVec(self.0.clone()) } } -/// Creates a new `BitVec` instance. +/// 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 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(), } diff --git a/crates/servicepoint_binding_c/src/brightness_grid.rs b/crates/servicepoint_binding_c/src/brightness_grid.rs index 6fa2c5a..a34ecf2 100644 --- a/crates/servicepoint_binding_c/src/brightness_grid.rs +++ b/crates/servicepoint_binding_c/src/brightness_grid.rs @@ -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; +/// A grid containing brightness values. +/// +/// # Examples +/// ```C +/// SPConnection connection = sp_connection_open("127.0.0.1:2342"); +/// if (connection == NULL) +/// return 1; +/// +/// SPBrightnessGrid grid = sp_brightness_grid_new(2, 2); +/// sp_brightness_grid_set(grid, 0, 0, 0); +/// sp_brightness_grid_set(grid, 1, 1, 10); +/// +/// SPCommand command = sp_command_char_brightness(grid); +/// sp_connection_free(connection); +/// ``` +pub struct SPBrightnessGrid(pub(crate) servicepoint::BrightnessGrid); -/// C-wrapper for grid containing brightness values. -#[derive(Clone)] -pub struct CBrightnessGrid(pub(crate) BrightnessGrid); +impl Clone for SPBrightnessGrid { + fn clone(&self) -> Self { + SPBrightnessGrid(self.0.clone()) + } +} -/// Creates a new `BrightnessGrid` with the specified dimensions. +/// Creates a new `SPBrightnessGrid` with the specified dimensions. /// -/// returns: `BrightnessGrid` initialized to 0. +/// 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::(), 1); + brightness_grid: *mut SPBrightnessGrid, +) -> SPByteSlice { + assert_eq!(core::mem::size_of::(), 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(), } diff --git a/crates/servicepoint_binding_c/src/c_slice.rs b/crates/servicepoint_binding_c/src/byte_slice.rs similarity index 66% rename from crates/servicepoint_binding_c/src/c_slice.rs rename to crates/servicepoint_binding_c/src/byte_slice.rs index 566213d..fbdda2a 100644 --- a/crates/servicepoint_binding_c/src/c_slice.rs +++ b/crates/servicepoint_binding_c/src/byte_slice.rs @@ -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 diff --git a/crates/servicepoint_binding_c/src/command.rs b/crates/servicepoint_binding_c/src/command.rs index 823e3d6..d98b99f 100644 --- a/crates/servicepoint_binding_c/src/command.rs +++ b/crates/servicepoint_binding_c/src/command.rs @@ -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. +impl Clone for SPCommand { + fn clone(&self) -> Self { + SPCommand(self.0.clone()) + } +} + +/// Tries to turn a `SPPacket` into a `SPCommand`. +/// +/// The packet is deallocated in the process. /// -/// Returns: pointer to new `Command` instance or NULL +/// Returns: pointer to new `SPCommand` 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 +/// - `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 `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_try_from_packet( - packet: *mut Packet, -) -> *mut Command { + packet: *mut SPPacket, +) -> *mut SPCommand { let packet = *Box::from_raw(packet); - match Command::try_from(packet) { + match servicepoint::Command::try_from(packet.0) { Err(_) => null_mut(), - Ok(command) => Box::into_raw(Box::new(command)), + Ok(command) => Box::into_raw(Box::new(SPCommand(command))), } } -/// Clones a `Command` instance. +/// Clones a `SPCommand` instance. /// /// # 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`. +/// - `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. +/// +///
+/// 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. +///
+/// +/// 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); } diff --git a/crates/servicepoint_binding_c/src/connection.rs b/crates/servicepoint_binding_c/src/connection.rs index 25b9cf7..846b607 100644 --- a/crates/servicepoint_binding_c/src/connection.rs +++ b/crates/servicepoint_binding_c/src/connection.rs @@ -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() +} + +/// 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: +/// +/// - `connection` points to a valid instance of `SPConnection` +/// - `command` points to a valid instance of `SPPacket` +/// - `command` is not used concurrently or after this call +#[no_mangle] +pub unsafe extern "C" fn sp_connection_send_command( + connection: *const SPConnection, + command: *mut SPCommand, +) -> bool { + let command = (*Box::from_raw(command)).0; + (*connection).0.send(command).is_ok() } -/// Closes and deallocates a `Connection`. +/// Closes and deallocates a `SPConnection`. /// /// # 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 `SPConnection` +/// - `connection` 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_free(connection: *mut SPConnection) { + _ = Box::from_raw(connection); } diff --git a/crates/servicepoint_binding_c/src/constants.rs b/crates/servicepoint_binding_c/src/constants.rs new file mode 100644 index 0000000..1a268f4 --- /dev/null +++ b/crates/servicepoint_binding_c/src/constants.rs @@ -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 for CompressionCode { + type Error = (); + + fn try_from(value: SPCompressionCode) -> Result { + CompressionCode::try_from(value as u16) + } +} diff --git a/crates/servicepoint_binding_c/src/cp437_grid.rs b/crates/servicepoint_binding_c/src/cp437_grid.rs index f14c71d..a8d4684 100644 --- a/crates/servicepoint_binding_c/src/cp437_grid.rs +++ b/crates/servicepoint_binding_c/src/cp437_grid.rs @@ -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); +/// +/// # 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 `Cp437Grid` with the specified dimensions. +/// Creates a new `SPCp437Grid` with the specified dimensions. /// -/// returns: `Cp437Grid` initialized to 0. +/// 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(), } diff --git a/crates/servicepoint_binding_c/src/lib.rs b/crates/servicepoint_binding_c/src/lib.rs index 0939b66..d6f839b 100644 --- a/crates/servicepoint_binding_c/src/lib.rs +++ b/crates/servicepoint_binding_c/src/lib.rs @@ -1,27 +1,46 @@ -//! C API wrapper for the `servicepoint` crate. - -pub use servicepoint::{ - CompressionCode, PIXEL_COUNT, PIXEL_HEIGHT, PIXEL_WIDTH, TILE_HEIGHT, - TILE_SIZE, TILE_WIDTH, -}; - -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; +//! 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 +//! #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 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::*; + +mod bit_vec; +mod brightness_grid; +mod byte_slice; +mod command; +mod connection; +mod constants; +mod cp437_grid; +mod packet; +mod pixel_grid; diff --git a/crates/servicepoint_binding_c/src/packet.rs b/crates/servicepoint_binding_c/src/packet.rs index 952ef1e..eac41b8 100644 --- a/crates/servicepoint_binding_c/src/packet.rs +++ b/crates/servicepoint_binding_c/src/packet.rs @@ -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: +/// +/// - `packet` points to a valid `SPPacket` +/// - `packet` is not written to concurrently +/// - the returned instance is freed in some way, either by using a consuming function or +/// by explicitly calling `sp_packet_free`. +#[no_mangle] +pub unsafe extern "C" fn sp_packet_clone( + packet: *const SPPacket, +) -> *mut SPPacket { + Box::into_raw(Box::new(SPPacket((*packet).0.clone()))) +} + +/// Deallocates a `SPPacket`. /// /// # 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 used concurrently or after this call #[no_mangle] -pub unsafe extern "C" fn sp_packet_dealloc(this: *mut Packet) { - _ = Box::from_raw(this) +pub unsafe extern "C" fn sp_packet_free(packet: *mut SPPacket) { + _ = Box::from_raw(packet) } diff --git a/crates/servicepoint_binding_c/src/pixel_grid.rs b/crates/servicepoint_binding_c/src/pixel_grid.rs index 10cff60..780c305 100644 --- a/crates/servicepoint_binding_c/src/pixel_grid.rs +++ b/crates/servicepoint_binding_c/src/pixel_grid.rs @@ -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(), } diff --git a/crates/servicepoint_binding_cs/Cargo.toml b/crates/servicepoint_binding_cs/Cargo.toml index e93b557..798292d 100644 --- a/crates/servicepoint_binding_cs/Cargo.toml +++ b/crates/servicepoint_binding_cs/Cargo.toml @@ -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 diff --git a/crates/servicepoint_binding_cs/README.md b/crates/servicepoint_binding_cs/README.md index 1248af7..0f5ee3d 100644 --- a/crates/servicepoint_binding_cs/README.md +++ b/crates/servicepoint_binding_cs/README.md @@ -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" ``` diff --git a/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs b/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs index 009de2d..d23b2b9 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs @@ -14,278 +14,1212 @@ public static unsafe partial class NativeMethods { const string __DllName = "servicepoint_binding_c"; - public const nuint TILE_SIZE = 8; - public const nuint TILE_WIDTH = 56; - public const nuint TILE_HEIGHT = 20; - - - /// Creates a new `BitVec` instance. # Arguments * `size`: size in bits. returns: `BitVec` with all bits set to false. # Panics When `size` is not divisible by 8. # Safety The caller has to make sure that: - the returned instance is freed in some way, either by using a consuming function or by explicitly calling `sp_bit_vec_dealloc`. + public const nuint SP_TILE_SIZE = 8; + public const nuint SP_TILE_WIDTH = 56; + public const nuint SP_TILE_HEIGHT = 20; + + + /// + /// Creates a new `SPBitVec` instance. + /// + /// # Arguments + /// + /// - `size`: size in bits. + /// + /// returns: `SPBitVec` with all bits set to false. Will never return NULL. + /// + /// # Panics + /// + /// When `size` is not divisible by 8. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_bit_vec_free`. + /// [DllImport(__DllName, EntryPoint = "sp_bit_vec_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CBitVec* sp_bit_vec_new(nuint size); - - /// Interpret the data as a series of bits and load then into a new `BitVec` instance. # Safety The caller has to make sure that: - `data` points to a valid memory location of at least `data_length` bytes in size. - the returned instance is freed in some way, either by using a consuming function or by explicitly calling `sp_bit_vec_dealloc`. + public static extern BitVec* sp_bit_vec_new(nuint size); + + /// + /// Interpret the data as a series of bits and load then into a new `SPBitVec` instance. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `data` points to a valid memory location of at least `data_length` + /// bytes in size. + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_bit_vec_free`. + /// [DllImport(__DllName, EntryPoint = "sp_bit_vec_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CBitVec* sp_bit_vec_load(byte* data, nuint data_length); - - /// Clones a `BitVec`. # Safety The caller has to make sure that: - `this` points to a valid `BitVec` - `this` 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`. + public static extern BitVec* sp_bit_vec_load(byte* data, nuint data_length); + + /// + /// Clones a `SPBitVec`. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` is not written to concurrently + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_bit_vec_free`. + /// [DllImport(__DllName, EntryPoint = "sp_bit_vec_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CBitVec* sp_bit_vec_clone(CBitVec* @this); - - /// Deallocates a `BitVec`. # 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` - [DllImport(__DllName, EntryPoint = "sp_bit_vec_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_bit_vec_dealloc(CBitVec* @this); - - /// Gets the value of a bit from the `BitVec`. # Arguments * `this`: instance to read from * `index`: the bit index to read returns: value of the bit # Panics When accessing `index` out of bounds. # Safety The caller has to make sure that: - `this` points to a valid `BitVec` - `this` is not written to concurrently + public static extern BitVec* sp_bit_vec_clone(BitVec* bit_vec); + + /// + /// Deallocates a `SPBitVec`. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` is not used concurrently or after this call + /// - `bit_vec` was not passed to another consuming function, e.g. to create a `SPCommand` + /// + [DllImport(__DllName, EntryPoint = "sp_bit_vec_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_bit_vec_free(BitVec* bit_vec); + + /// + /// Gets the value of a bit from the `SPBitVec`. + /// + /// # Arguments + /// + /// - `bit_vec`: instance to read from + /// - `index`: the bit index to read + /// + /// returns: value of the bit + /// + /// # Panics + /// + /// When accessing `index` out of bounds. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` is not written to concurrently + /// [DllImport(__DllName, EntryPoint = "sp_bit_vec_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.U1)] - public static extern bool sp_bit_vec_get(CBitVec* @this, nuint index); - - /// Sets the value of a bit in the `BitVec`. # Arguments * `this`: instance to write to * `index`: the bit index to edit * `value`: the value to set the bit to returns: old value of the bit # Panics When accessing `index` out of bounds. # Safety The caller has to make sure that: - `this` points to a valid `BitVec` - `this` is not written to or read from concurrently + public static extern bool sp_bit_vec_get(BitVec* bit_vec, nuint index); + + /// + /// Sets the value of a bit in the `SPBitVec`. + /// + /// # Arguments + /// + /// - `bit_vec`: instance to write to + /// - `index`: the bit index to edit + /// - `value`: the value to set the bit to + /// + /// returns: old value of the bit + /// + /// # Panics + /// + /// When accessing `index` out of bounds. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` is not written to or read from concurrently + /// [DllImport(__DllName, EntryPoint = "sp_bit_vec_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_bit_vec_set(CBitVec* @this, nuint index, [MarshalAs(UnmanagedType.U1)] bool value); - - /// Sets the value of all bits in the `BitVec`. # Arguments * `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 + public static extern void sp_bit_vec_set(BitVec* bit_vec, nuint index, [MarshalAs(UnmanagedType.U1)] bool value); + + /// + /// Sets the value of all bits in the `SPBitVec`. + /// + /// # Arguments + /// + /// - `bit_vec`: instance to write to + /// - `value`: the value to set all bits to + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bit_vec` points to a valid `SPBitVec` + /// - `bit_vec` is not written to or read from concurrently + /// [DllImport(__DllName, EntryPoint = "sp_bit_vec_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_bit_vec_fill(CBitVec* @this, [MarshalAs(UnmanagedType.U1)] bool value); - - /// Gets the length of the `BitVec` in bits. # Safety The caller has to make sure that: - `this` points to a valid `BitVec` + public static extern void sp_bit_vec_fill(BitVec* bit_vec, [MarshalAs(UnmanagedType.U1)] bool value); + + /// + /// Gets the length of the `SPBitVec` in bits. + /// + /// # Arguments + /// + /// - `bit_vec`: instance to write to + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bit_vec` points to a valid `SPBitVec` + /// [DllImport(__DllName, EntryPoint = "sp_bit_vec_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern nuint sp_bit_vec_len(CBitVec* @this); - - /// Returns true if length is 0. # Safety The caller has to make sure that: - `this` points to a valid `BitVec` + public static extern nuint sp_bit_vec_len(BitVec* bit_vec); + + /// + /// Returns true if length is 0. + /// + /// # Arguments + /// + /// - `bit_vec`: instance to write to + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `bit_vec` points to a valid `SPBitVec` + /// [DllImport(__DllName, EntryPoint = "sp_bit_vec_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.U1)] - public static extern bool sp_bit_vec_is_empty(CBitVec* @this); - - /// Gets an unsafe reference to the data of the `BitVec` instance. ## 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 + public static extern bool sp_bit_vec_is_empty(BitVec* bit_vec); + + /// + /// 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: + /// + /// - `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 + /// [DllImport(__DllName, EntryPoint = "sp_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CByteSlice sp_bit_vec_unsafe_data_ref(CBitVec* @this); - - /// Creates a new `BrightnessGrid` with the specified dimensions. returns: `BrightnessGrid` 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_brightness_grid_dealloc`. + public static extern ByteSlice sp_bit_vec_unsafe_data_ref(BitVec* bit_vec); + + /// + /// Creates a new `SPBrightnessGrid` with the specified dimensions. + /// + /// returns: `SPBrightnessGrid` initialized to 0. Will never return NULL. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_brightness_grid_free`. + /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CBrightnessGrid* sp_brightness_grid_new(nuint width, nuint height); - - /// Loads a `BrightnessGrid` with the specified dimensions from the provided data. # Panics When the provided `data_length` is not sufficient for the `height` and `width` # Safety The caller has to make sure that: - `data` points to a valid memory location of at least `data_length` bytes in size. - the returned instance is freed in some way, either by using a consuming function or by explicitly calling `sp_brightness_grid_dealloc`. + public static extern BrightnessGrid* sp_brightness_grid_new(nuint width, nuint height); + + /// + /// Loads a `SPBrightnessGrid` with the specified dimensions from the provided data. + /// + /// # Panics + /// + /// When the provided `data_length` is not sufficient for the `height` and `width` + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `data` points to a valid memory location of at least `data_length` + /// bytes in size. + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_brightness_grid_free`. + /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CBrightnessGrid* sp_brightness_grid_load(nuint width, nuint height, byte* data, nuint data_length); - - /// Clones a `BrightnessGrid`. # Safety The caller has to make sure that: - `this` points to a valid `BrightnessGrid` - `this` 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`. + public static extern BrightnessGrid* sp_brightness_grid_load(nuint width, nuint height, byte* data, nuint data_length); + + /// + /// Clones a `SPBrightnessGrid`. + /// + /// # Arguments + /// + /// - `brightness_grid`: instance to read from + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// - `brightness_grid` is not written to concurrently + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_brightness_grid_free`. + /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CBrightnessGrid* sp_brightness_grid_clone(CBrightnessGrid* @this); - - /// Deallocates a `BrightnessGrid`. # 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` - [DllImport(__DllName, EntryPoint = "sp_brightness_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_brightness_grid_dealloc(CBrightnessGrid* @this); - - /// Gets the current value at the specified position. # Arguments * `this`: instance to read from * `x` and `y`: position of the cell to read # Panics When accessing `x` or `y` out of bounds. # Safety The caller has to make sure that: - `this` points to a valid `BrightnessGrid` - `this` is not written to concurrently + public static extern BrightnessGrid* sp_brightness_grid_clone(BrightnessGrid* brightness_grid); + + /// + /// Deallocates a `SPBrightnessGrid`. + /// + /// # Arguments + /// + /// - `brightness_grid`: instance to read from + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// - `brightness_grid` is not used concurrently or after this call + /// - `brightness_grid` was not passed to another consuming function, e.g. to create a `SPCommand` + /// + [DllImport(__DllName, EntryPoint = "sp_brightness_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_brightness_grid_free(BrightnessGrid* brightness_grid); + + /// + /// Gets the current value at the specified position. + /// + /// # Arguments + /// + /// - `brightness_grid`: instance to read from + /// - `x` and `y`: position of the cell to read + /// + /// # Panics + /// + /// When accessing `x` or `y` out of bounds. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// - `brightness_grid` is not written to concurrently + /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern byte sp_brightness_grid_get(CBrightnessGrid* @this, nuint x, nuint y); - - /// Sets the value of the specified position in the `BrightnessGrid`. # Arguments * `this`: 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. # Safety The caller has to make sure that: - `this` points to a valid `BitVec` - `this` is not written to or read from concurrently + public static extern byte sp_brightness_grid_get(BrightnessGrid* brightness_grid, nuint x, nuint y); + + /// + /// Sets the value of the specified position in the `SPBrightnessGrid`. + /// + /// # Arguments + /// + /// - `brightness_grid`: instance to write to + /// - `x` and `y`: position of the cell + /// - `value`: the value to write to the cell + /// + /// returns: old value of the cell + /// + /// # Panics + /// + /// - When accessing `x` or `y` out of bounds. + /// - When providing an invalid brightness value + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `brightness_grid` points to a valid `SPBitVec` + /// - `brightness_grid` is not written to or read from concurrently + /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_brightness_grid_set(CBrightnessGrid* @this, nuint x, nuint y, byte value); - - /// Sets the value of all cells in the `BrightnessGrid`. # Arguments * `this`: 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 `BrightnessGrid` - `this` is not written to or read from concurrently + public static extern void sp_brightness_grid_set(BrightnessGrid* brightness_grid, nuint x, nuint y, byte value); + + /// + /// Sets the value of all cells in the `SPBrightnessGrid`. + /// + /// # Arguments + /// + /// - `brightness_grid`: instance to write to + /// - `value`: the value to set all cells to + /// + /// # Panics + /// + /// - When providing an invalid brightness value + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// - `brightness_grid` is not written to or read from concurrently + /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_brightness_grid_fill(CBrightnessGrid* @this, byte value); - - /// Gets the width of the `BrightnessGrid` instance. # Arguments * `this`: instance to read from # Safety The caller has to make sure that: - `this` points to a valid `BrightnessGrid` + public static extern void sp_brightness_grid_fill(BrightnessGrid* brightness_grid, byte value); + + /// + /// Gets the width of the `SPBrightnessGrid` instance. + /// + /// # Arguments + /// + /// - `brightness_grid`: instance to read from + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern nuint sp_brightness_grid_width(CBrightnessGrid* @this); - - /// Gets the height of the `BrightnessGrid` instance. # Arguments * `this`: instance to read from # Safety The caller has to make sure that: - `this` points to a valid `BrightnessGrid` + public static extern nuint sp_brightness_grid_width(BrightnessGrid* brightness_grid); + + /// + /// Gets the height of the `SPBrightnessGrid` instance. + /// + /// # Arguments + /// + /// - `brightness_grid`: instance to read from + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `brightness_grid` points to a valid `SPBrightnessGrid` + /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern nuint sp_brightness_grid_height(CBrightnessGrid* @this); - - /// Gets an unsafe reference to the data of the `BrightnessGrid` instance. ## 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 + public static extern nuint sp_brightness_grid_height(BrightnessGrid* brightness_grid); + + /// + /// 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: + /// + /// - `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 + /// [DllImport(__DllName, EntryPoint = "sp_brightness_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CByteSlice sp_brightness_grid_unsafe_data_ref(CBrightnessGrid* @this); - - /// Creates a new `Cp437Grid` with the specified dimensions. returns: `Cp437Grid` 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`. - [DllImport(__DllName, EntryPoint = "sp_cp437_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CCp437Grid* sp_cp437_grid_new(nuint width, nuint height); - - /// Loads a `Cp437Grid` with the specified dimensions from the provided data. # Panics When the provided `data_length` is not sufficient for the `height` and `width` # Safety The caller has to make sure that: - `data` points to a valid memory location of at least `data_length` bytes in size. - the returned instance is freed in some way, either by using a consuming function or by explicitly calling `sp_cp437_grid_dealloc`. - [DllImport(__DllName, EntryPoint = "sp_cp437_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CCp437Grid* sp_cp437_grid_load(nuint width, nuint height, byte* data, nuint data_length); - - /// Clones a `Cp437Grid`. # Safety The caller has to make sure that: - `this` points to a valid `Cp437Grid` - `this` 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`. - [DllImport(__DllName, EntryPoint = "sp_cp437_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CCp437Grid* sp_cp437_grid_clone(CCp437Grid* @this); - - /// Deallocates a `Cp437Grid`. # 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` - [DllImport(__DllName, EntryPoint = "sp_cp437_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_cp437_grid_dealloc(CCp437Grid* @this); - - /// Gets the current value at the specified position. # Arguments * `this`: instance to read from * `x` and `y`: position of the cell to read # Panics When accessing `x` or `y` out of bounds. # Safety The caller has to make sure that: - `this` points to a valid `Cp437Grid` - `this` is not written to concurrently - [DllImport(__DllName, EntryPoint = "sp_cp437_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern byte sp_cp437_grid_get(CCp437Grid* @this, nuint x, nuint y); - - /// Sets the value of the specified position in the `Cp437Grid`. # Arguments * `this`: 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. # Safety The caller has to make sure that: - `this` points to a valid `BitVec` - `this` is not written to or read from concurrently - [DllImport(__DllName, EntryPoint = "sp_cp437_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_cp437_grid_set(CCp437Grid* @this, nuint x, nuint y, byte value); - - /// Sets the value of all cells in the `Cp437Grid`. # Arguments * `this`: 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 - [DllImport(__DllName, EntryPoint = "sp_cp437_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_cp437_grid_fill(CCp437Grid* @this, byte value); - - /// Gets the width of the `Cp437Grid` instance. # Arguments * `this`: instance to read from # Safety The caller has to make sure that: - `this` points to a valid `Cp437Grid` - [DllImport(__DllName, EntryPoint = "sp_cp437_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern nuint sp_cp437_grid_width(CCp437Grid* @this); - - /// Gets the height of the `Cp437Grid` instance. # Arguments * `this`: instance to read from # Safety The caller has to make sure that: - `this` points to a valid `Cp437Grid` - [DllImport(__DllName, EntryPoint = "sp_cp437_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern nuint sp_cp437_grid_height(CCp437Grid* @this); - - /// Gets an unsafe reference to the data of the `Cp437Grid` instance. ## 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 - [DllImport(__DllName, EntryPoint = "sp_cp437_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CByteSlice sp_cp437_grid_unsafe_data_ref(CCp437Grid* @this); - - /// 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`. + public static extern ByteSlice sp_brightness_grid_unsafe_data_ref(BrightnessGrid* brightness_grid); + + /// + /// 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: + /// + /// - `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`. + /// [DllImport(__DllName, EntryPoint = "sp_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern Command* sp_command_try_from_packet(Packet* packet); - /// Clones a `Command` instance. # 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`. + /// + /// 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`. + /// [DllImport(__DllName, EntryPoint = "sp_command_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern Command* sp_command_clone(Command* original); - - /// Allocates a new `Command::Clear` instance. # 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`. + public static extern Command* sp_command_clone(Command* command); + + /// + /// 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 `SPCommand` instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_command_free`. + /// [DllImport(__DllName, EntryPoint = "sp_command_clear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern Command* sp_command_clear(); - /// Allocates a new `Command::HardReset` instance. # 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`. + /// + /// 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 `SPCommand` instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_command_free`. + /// [DllImport(__DllName, EntryPoint = "sp_command_hard_reset", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern Command* sp_command_hard_reset(); - /// Allocates a new `Command::FadeOut` instance. # 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`. + /// + /// 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 `SPCommand` instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_command_free`. + /// [DllImport(__DllName, EntryPoint = "sp_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern Command* sp_command_fade_out(); - /// Allocates a new `Command::Brightness` instance for setting the brightness of all tiles to the same value. # Panics - When the provided brightness value is out of range (0-11). # 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`. + /// + /// Set the brightness of all tiles to the same value. + /// + /// Returns: a new `Command::Brightness` instance. Will never return NULL. + /// + /// # Panics + /// + /// - When the provided brightness value is out of range (0-11). + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_command_free`. + /// [DllImport(__DllName, EntryPoint = "sp_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern Command* sp_command_brightness(byte brightness); - /// Allocates a new `Command::CharBrightness` instance. The passed `ByteGrid` gets consumed. # 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`. + /// + /// 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: + /// + /// - `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`. + /// [DllImport(__DllName, EntryPoint = "sp_command_char_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern Command* sp_command_char_brightness(nuint x, nuint y, CBrightnessGrid* byte_grid); - - /// Allocates a new `Command::BitmapLinear` instance. The passed `BitVec` gets consumed. # Safety The caller has to make sure that: - `bit_vec` points to a valid instance of `BitVec` - `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`. + public static extern Command* sp_command_char_brightness(nuint x, nuint y, BrightnessGrid* grid); + + /// + /// 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 `SPBitVec` + /// - `bit_vec` is not used concurrently or after this call + /// - `compression` matches one of the allowed enum values + /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_command_free`. + /// [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern Command* sp_command_bitmap_linear(nuint offset, CBitVec* bit_vec, CompressionCode compression); - - /// Allocates a new `Command::BitmapLinearAnd` instance. The passed `BitVec` gets consumed. # Safety The caller has to make sure that: - `bit_vec` points to a valid instance of `BitVec` - `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`. + public static extern Command* sp_command_bitmap_linear(nuint offset, BitVec* bit_vec, CompressionCode compression); + + /// + /// 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 `SPBitVec` + /// - `bit_vec` is not used concurrently or after this call + /// - `compression` matches one of the allowed enum values + /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_command_free`. + /// [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_and", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern Command* sp_command_bitmap_linear_and(nuint offset, CBitVec* bit_vec, CompressionCode compression); - - /// Allocates a new `Command::BitmapLinearOr` instance. The passed `BitVec` gets consumed. # Safety The caller has to make sure that: - `bit_vec` points to a valid instance of `BitVec` - `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`. + public static extern Command* sp_command_bitmap_linear_and(nuint offset, BitVec* bit_vec, CompressionCode compression); + + /// + /// 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 `SPBitVec` + /// - `bit_vec` is not used concurrently or after this call + /// - `compression` matches one of the allowed enum values + /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_command_free`. + /// [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_or", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern Command* sp_command_bitmap_linear_or(nuint offset, CBitVec* bit_vec, CompressionCode compression); - - /// Allocates a new `Command::BitmapLinearXor` instance. The passed `BitVec` gets consumed. # Safety The caller has to make sure that: - `bit_vec` points to a valid instance of `BitVec` - `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`. + public static extern Command* sp_command_bitmap_linear_or(nuint offset, BitVec* bit_vec, CompressionCode compression); + + /// + /// 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 `SPBitVec` + /// - `bit_vec` is not used concurrently or after this call + /// - `compression` matches one of the allowed enum values + /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_command_free`. + /// [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_xor", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern Command* sp_command_bitmap_linear_xor(nuint offset, CBitVec* bit_vec, CompressionCode compression); - - /// Allocates a new `Command::Cp437Data` instance. The passed `ByteGrid` gets consumed. # 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`. + public static extern Command* sp_command_bitmap_linear_xor(nuint offset, BitVec* bit_vec, CompressionCode compression); + + /// + /// 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: + /// + /// - `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`. + /// [DllImport(__DllName, EntryPoint = "sp_command_cp437_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern Command* sp_command_cp437_data(nuint x, nuint y, CCp437Grid* byte_grid); - - /// Allocates a new `Command::BitmapLinearWin` instance. The passed `PixelGrid` gets consumed. # Safety The caller has to make sure that: - `pixel_grid` points to a valid instance of `PixelGrid` - `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`. + public static extern Command* sp_command_cp437_data(nuint x, nuint y, Cp437Grid* grid); + + /// + /// 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 `SPPixelGrid` + /// - `pixel_grid` is not used concurrently or after this call + /// - `compression` matches one of the allowed enum values + /// - the returned `SPCommand` instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_command_free`. + /// [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern Command* sp_command_bitmap_linear_win(nuint x, nuint y, PixelGrid* pixel_grid, CompressionCode compression_code); - /// Deallocates a `Command`. # 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` - [DllImport(__DllName, EntryPoint = "sp_command_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_command_dealloc(Command* ptr); - - /// Creates a new instance of `Connection`. returns: NULL if connection fails, or connected instance # Panics Bad string encoding # Safety The caller has to make sure that: - the returned instance is freed in some way, either by using a consuming function or by explicitly calling `sp_connection_dealloc`. + /// + /// Deallocates a `SPCommand`. + /// + /// # Examples + /// + /// ```C + /// SPCommand c = sp_command_clear(); + /// sp_command_free(c); + /// ``` + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `command` points to a valid `SPCommand` + /// - `command` is not used concurrently or after this call + /// - `command` was not passed to another consuming function, e.g. to create a `SPPacket` + /// + [DllImport(__DllName, EntryPoint = "sp_command_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_command_free(Command* command); + + /// + /// Creates a new instance of `SPConnection`. + /// + /// returns: NULL if connection fails, or connected instance + /// + /// # Panics + /// + /// Bad string encoding + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_connection_free`. + /// [DllImport(__DllName, EntryPoint = "sp_connection_open", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern Connection* sp_connection_open(byte* host); - /// Sends a `Packet` to the display using the `Connection`. The passed `Packet` gets consumed. returns: true in case of success # Safety The caller has to make sure that: - `connection` points to a valid instance of `Connection` - `packet` points to a valid instance of `Packet` - `packet` is not used concurrently or after this call - [DllImport(__DllName, EntryPoint = "sp_connection_send", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + /// + /// Sends a `SPPacket` to the display using the `SPConnection`. + /// + /// The passed `packet` gets consumed. + /// + /// returns: true in case of success + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `connection` points to a valid instance of `SPConnection` + /// - `packet` points to a valid instance of `SPPacket` + /// - `packet` is not used concurrently or after this call + /// + [DllImport(__DllName, EntryPoint = "sp_connection_send_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.U1)] - public static extern bool sp_connection_send(Connection* connection, Packet* packet); + public static extern bool sp_connection_send_packet(Connection* connection, Packet* packet); + + /// + /// 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: + /// + /// - `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 + /// + [DllImport(__DllName, EntryPoint = "sp_connection_send_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [return: MarshalAs(UnmanagedType.U1)] + public static extern bool sp_connection_send_command(Connection* connection, Command* command); + + /// + /// 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 + /// + [DllImport(__DllName, EntryPoint = "sp_connection_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_connection_free(Connection* connection); + + /// + /// 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_free`. + /// + [DllImport(__DllName, EntryPoint = "sp_cp437_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern Cp437Grid* sp_cp437_grid_new(nuint width, nuint height); + + /// + /// Loads a `SPCp437Grid` with the specified dimensions from the provided data. + /// + /// Will never return NULL. + /// + /// # Panics + /// + /// When the provided `data_length` is not sufficient for the `height` and `width` + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `data` points to a valid memory location of at least `data_length` + /// bytes in size. + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_cp437_grid_free`. + /// + [DllImport(__DllName, EntryPoint = "sp_cp437_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern Cp437Grid* sp_cp437_grid_load(nuint width, nuint height, byte* data, nuint data_length); + + /// + /// Clones a `SPCp437Grid`. + /// + /// Will never return NULL. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `cp437_grid` points to a valid `SPCp437Grid` + /// - `cp437_grid` is not written to concurrently + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_cp437_grid_free`. + /// + [DllImport(__DllName, EntryPoint = "sp_cp437_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern Cp437Grid* sp_cp437_grid_clone(Cp437Grid* cp437_grid); + + /// + /// Deallocates a `SPCp437Grid`. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `cp437_grid` points to a valid `SPCp437Grid` + /// - `cp437_grid` is not used concurrently or after cp437_grid call + /// - `cp437_grid` was not passed to another consuming function, e.g. to create a `SPCommand` + /// + [DllImport(__DllName, EntryPoint = "sp_cp437_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_cp437_grid_free(Cp437Grid* cp437_grid); + + /// + /// Gets the current value at the specified position. + /// + /// # Arguments + /// + /// - `cp437_grid`: instance to read from + /// - `x` and `y`: position of the cell to read + /// + /// # Panics + /// + /// When accessing `x` or `y` out of bounds. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `cp437_grid` points to a valid `SPCp437Grid` + /// - `cp437_grid` is not written to concurrently + /// + [DllImport(__DllName, EntryPoint = "sp_cp437_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern byte sp_cp437_grid_get(Cp437Grid* cp437_grid, nuint x, nuint y); + + /// + /// Sets the value of the specified position in the `SPCp437Grid`. + /// + /// # Arguments + /// + /// - `cp437_grid`: instance to write to + /// - `x` and `y`: position of the cell + /// - `value`: the value to write to the cell + /// + /// returns: old value of the cell + /// + /// # Panics + /// + /// When accessing `x` or `y` out of bounds. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `cp437_grid` points to a valid `SPBitVec` + /// - `cp437_grid` is not written to or read from concurrently + /// + [DllImport(__DllName, EntryPoint = "sp_cp437_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_cp437_grid_set(Cp437Grid* cp437_grid, nuint x, nuint y, byte value); + + /// + /// Sets the value of all cells in the `SPCp437Grid`. + /// + /// # Arguments + /// + /// - `cp437_grid`: instance to write to + /// - `value`: the value to set all cells to + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `cp437_grid` points to a valid `SPCp437Grid` + /// - `cp437_grid` is not written to or read from concurrently + /// + [DllImport(__DllName, EntryPoint = "sp_cp437_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_cp437_grid_fill(Cp437Grid* cp437_grid, byte value); + + /// + /// Gets the width of the `SPCp437Grid` instance. + /// + /// # Arguments + /// + /// - `cp437_grid`: instance to read from + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `cp437_grid` points to a valid `SPCp437Grid` + /// + [DllImport(__DllName, EntryPoint = "sp_cp437_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern nuint sp_cp437_grid_width(Cp437Grid* cp437_grid); + + /// + /// Gets the height of the `SPCp437Grid` instance. + /// + /// # Arguments + /// + /// - `cp437_grid`: instance to read from + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `cp437_grid` points to a valid `SPCp437Grid` + /// + [DllImport(__DllName, EntryPoint = "sp_cp437_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern nuint sp_cp437_grid_height(Cp437Grid* cp437_grid); + + /// + /// Gets an unsafe reference to the data of the `SPCp437Grid` instance. + /// + /// Will never return NULL. + /// + /// ## Safety + /// + /// The caller has to make sure that: + /// + /// - `cp437_grid` points to a valid `SPCp437Grid` + /// - the returned memory range is never accessed after the passed `SPCp437Grid` has been freed + /// - the returned memory range is never accessed concurrently, either via the `SPCp437Grid` or directly + /// + [DllImport(__DllName, EntryPoint = "sp_cp437_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern ByteSlice sp_cp437_grid_unsafe_data_ref(Cp437Grid* cp437_grid); + + /// + /// Turns a `SPCommand` into a `SPPacket`. + /// The `SPCommand` gets consumed. + /// + /// Will never return NULL. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `SPCommand` points to a valid instance of `SPCommand` + /// - `SPCommand` is not used concurrently or after this call + /// - the returned `SPPacket` instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_packet_free`. + /// + [DllImport(__DllName, EntryPoint = "sp_packet_from_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern Packet* sp_packet_from_command(Command* command); - /// Closes and deallocates a `Connection`. # Safety The caller has to make sure that: - `this` points to a valid `Connection` - `this` is not used concurrently or after this call - [DllImport(__DllName, EntryPoint = "sp_connection_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_connection_dealloc(Connection* ptr); + /// + /// 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 + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `data` points to a valid memory region of at least `length` bytes + /// - `data` is not written to concurrently + /// - the returned `SPPacket` instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_packet_free`. + /// + [DllImport(__DllName, EntryPoint = "sp_packet_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern Packet* sp_packet_try_load(byte* data, nuint length); - /// Creates a new `PixelGrid` with the specified dimensions. # Arguments * `width`: size in pixels in x-direction * `height`: size in pixels in y-direction returns: `PixelGrid` initialized to all pixels off # Panics - when the width is not dividable by 8 # Safety The caller has to make sure that: - the returned instance is freed in some way, either by using a consuming function or by explicitly calling `sp_pixel_grid_dealloc`. + /// + /// Clones a `SPPacket`. + /// + /// Will never return NULL. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `packet` points to a valid `SPPacket` + /// - `packet` is not written to concurrently + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_packet_free`. + /// + [DllImport(__DllName, EntryPoint = "sp_packet_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern Packet* sp_packet_clone(Packet* packet); + + /// + /// 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 + /// + [DllImport(__DllName, EntryPoint = "sp_packet_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_packet_free(Packet* packet); + + /// + /// Creates a new `SPPixelGrid` with the specified dimensions. + /// + /// # Arguments + /// + /// - `width`: size in pixels in x-direction + /// - `height`: size in pixels in y-direction + /// + /// returns: `SPPixelGrid` initialized to all pixels off. Will never return NULL. + /// + /// # Panics + /// + /// - when the width is not dividable by 8 + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_pixel_grid_free`. + /// [DllImport(__DllName, EntryPoint = "sp_pixel_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern PixelGrid* sp_pixel_grid_new(nuint width, nuint height); - /// Loads a `PixelGrid` with the specified dimensions from the provided data. # Arguments * `width`: size in pixels in x-direction * `height`: size in pixels in y-direction returns: `PixelGrid` that contains a copy of the provided data # Panics - when the dimensions and data size do not match exactly. - when the width is not dividable by 8 # Safety The caller has to make sure that: - `data` points to a valid memory location of at least `data_length` bytes in size. - the returned instance is freed in some way, either by using a consuming function or by explicitly calling `sp_pixel_grid_dealloc`. + /// + /// 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 + /// + /// returns: `SPPixelGrid` that contains a copy of the provided data. Will never return NULL. + /// + /// # Panics + /// + /// - when the dimensions and data size do not match exactly. + /// - when the width is not dividable by 8 + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `data` points to a valid memory location of at least `data_length` bytes in size. + /// - the returned instance is freed in some way, either by using a consuming function or + /// by explicitly calling `sp_pixel_grid_free`. + /// [DllImport(__DllName, EntryPoint = "sp_pixel_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern PixelGrid* sp_pixel_grid_load(nuint width, nuint height, byte* data, nuint data_length); - /// Clones a `PixelGrid`. # Safety The caller has to make sure that: - `this` points to a valid `PixelGrid` - `this` 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`. + /// + /// Clones a `SPPixelGrid`. + /// + /// Will never return NULL. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `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_free`. + /// [DllImport(__DllName, EntryPoint = "sp_pixel_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern PixelGrid* sp_pixel_grid_clone(PixelGrid* @this); - - /// Deallocates a `PixelGrid`. # 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` - [DllImport(__DllName, EntryPoint = "sp_pixel_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_pixel_grid_dealloc(PixelGrid* @this); - - /// Gets the current value at the specified position in the `PixelGrid`. # Arguments * `this`: instance to read from * `x` and `y`: position of the cell to read # Panics When accessing `x` or `y` out of bounds. # Safety The caller has to make sure that: - `this` points to a valid `PixelGrid` - `this` is not written to concurrently + public static extern PixelGrid* sp_pixel_grid_clone(PixelGrid* pixel_grid); + + /// + /// Deallocates a `SPPixelGrid`. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `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` + /// + [DllImport(__DllName, EntryPoint = "sp_pixel_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void sp_pixel_grid_free(PixelGrid* pixel_grid); + + /// + /// Gets the current value at the specified position in the `SPPixelGrid`. + /// + /// # Arguments + /// + /// - `pixel_grid`: instance to read from + /// - `x` and `y`: position of the cell to read + /// + /// # Panics + /// + /// When accessing `x` or `y` out of bounds. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `pixel_grid` points to a valid `SPPixelGrid` + /// - `pixel_grid` is not written to concurrently + /// [DllImport(__DllName, EntryPoint = "sp_pixel_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.U1)] - public static extern bool sp_pixel_grid_get(PixelGrid* @this, nuint x, nuint y); - - /// Sets the value of the specified position in the `PixelGrid`. # Arguments * `this`: 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. # Safety The caller has to make sure that: - `this` points to a valid `PixelGrid` - `this` is not written to or read from concurrently + public static extern bool sp_pixel_grid_get(PixelGrid* pixel_grid, nuint x, nuint y); + + /// + /// Sets the value of the specified position in the `SPPixelGrid`. + /// + /// # Arguments + /// + /// - `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 + /// + /// # Panics + /// + /// When accessing `x` or `y` out of bounds. + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `pixel_grid` points to a valid `SPPixelGrid` + /// - `pixel_grid` is not written to or read from concurrently + /// [DllImport(__DllName, EntryPoint = "sp_pixel_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_pixel_grid_set(PixelGrid* @this, nuint x, nuint y, [MarshalAs(UnmanagedType.U1)] bool value); - - /// Sets the state of all pixels in the `PixelGrid`. # Arguments * `this`: 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 + public static extern void sp_pixel_grid_set(PixelGrid* pixel_grid, nuint x, nuint y, [MarshalAs(UnmanagedType.U1)] bool value); + + /// + /// Sets the state of all pixels in the `SPPixelGrid`. + /// + /// # Arguments + /// + /// - `pixel_grid`: instance to write to + /// - `value`: the value to set all pixels to + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `pixel_grid` points to a valid `SPPixelGrid` + /// - `pixel_grid` is not written to or read from concurrently + /// [DllImport(__DllName, EntryPoint = "sp_pixel_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_pixel_grid_fill(PixelGrid* @this, [MarshalAs(UnmanagedType.U1)] bool value); - - /// Gets the width in pixels of the `PixelGrid` instance. # Arguments * `this`: instance to read from # Safety The caller has to make sure that: - `this` points to a valid `PixelGrid` + public static extern void sp_pixel_grid_fill(PixelGrid* pixel_grid, [MarshalAs(UnmanagedType.U1)] bool value); + + /// + /// Gets the width in pixels of the `SPPixelGrid` instance. + /// + /// # Arguments + /// + /// - `pixel_grid`: instance to read from + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `pixel_grid` points to a valid `SPPixelGrid` + /// [DllImport(__DllName, EntryPoint = "sp_pixel_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern nuint sp_pixel_grid_width(PixelGrid* @this); - - /// Gets the height in pixels of the `PixelGrid` instance. # Arguments * `this`: instance to read from # Safety The caller has to make sure that: - `this` points to a valid `PixelGrid` + public static extern nuint sp_pixel_grid_width(PixelGrid* pixel_grid); + + /// + /// Gets the height in pixels of the `SPPixelGrid` instance. + /// + /// # Arguments + /// + /// - `pixel_grid`: instance to read from + /// + /// # Safety + /// + /// The caller has to make sure that: + /// + /// - `pixel_grid` points to a valid `SPPixelGrid` + /// [DllImport(__DllName, EntryPoint = "sp_pixel_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern nuint sp_pixel_grid_height(PixelGrid* @this); - - /// Gets an unsafe reference to the data of the `PixelGrid` 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 + public static extern nuint sp_pixel_grid_height(PixelGrid* pixel_grid); + + /// + /// Gets an unsafe reference to the data of the `SPPixelGrid` instance. + /// + /// ## Safety + /// + /// The caller has to make sure that: + /// + /// - `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 + /// [DllImport(__DllName, EntryPoint = "sp_pixel_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern CByteSlice sp_pixel_grid_unsafe_data_ref(PixelGrid* @this); - - /// Turns a `Command` into a `Packet`. The `Command` gets consumed. # 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`. - [DllImport(__DllName, EntryPoint = "sp_packet_from_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern Packet* sp_packet_from_command(Command* command); - - /// Tries to load a `Packet` from the passed array with the specified length. returns: NULL in case of an error, pointer to the allocated packet otherwise # Safety The caller has to make sure that: - `data` points to a valid memory region of at least `length` bytes - `data` is not written to concurrently - the returned `Packet` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_packet_dealloc`. - [DllImport(__DllName, EntryPoint = "sp_packet_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern Packet* sp_packet_try_load(byte* data, nuint length); - - /// Deallocates a `Packet`. # Safety The caller has to make sure that: - `this` points to a valid `Packet` - `this` is not used concurrently or after this call - [DllImport(__DllName, EntryPoint = "sp_packet_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void sp_packet_dealloc(Packet* @this); + public static extern ByteSlice sp_pixel_grid_unsafe_data_ref(PixelGrid* pixel_grid); } [StructLayout(LayoutKind.Sequential)] - public unsafe partial struct CBitVec + public unsafe partial struct BitVec { } [StructLayout(LayoutKind.Sequential)] - public unsafe partial struct CBrightnessGrid + public unsafe partial struct BrightnessGrid { } [StructLayout(LayoutKind.Sequential)] - public unsafe partial struct CCp437Grid + public unsafe partial struct ByteSlice { + public byte* start; + public nuint length; } [StructLayout(LayoutKind.Sequential)] - public unsafe partial struct CByteSlice + public unsafe partial struct Command { - public byte* start; - public nuint length; } [StructLayout(LayoutKind.Sequential)] @@ -294,7 +1228,7 @@ public unsafe partial struct Connection } [StructLayout(LayoutKind.Sequential)] - public unsafe partial struct PixelGrid + public unsafe partial struct Cp437Grid { } @@ -303,23 +1237,12 @@ public unsafe partial struct Packet { } - - public enum Command + [StructLayout(LayoutKind.Sequential)] + public unsafe partial struct PixelGrid { - Clear, - Cp437Data, - BitmapLinearWin, - Brightness, - CharBrightness, - BitmapLinear, - BitmapLinearAnd, - BitmapLinearOr, - BitmapLinearXor, - HardReset, - FadeOut, - BitmapLegacy, } + public enum CompressionCode : ushort { Uncompressed = 0, diff --git a/crates/servicepoint_binding_cs/ServicePoint/BitVec.cs b/crates/servicepoint_binding_cs/ServicePoint/BitVec.cs index 53ee65c..2abe78c 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/BitVec.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/BitVec.cs @@ -2,7 +2,7 @@ namespace ServicePoint; -public sealed class BitVec : SpNativeInstance +public sealed class BitVec : SpNativeInstance { public static BitVec New(int size) { @@ -80,12 +80,9 @@ public Span Data } } - 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); } diff --git a/crates/servicepoint_binding_cs/ServicePoint/BrightnessGrid.cs b/crates/servicepoint_binding_cs/ServicePoint/BrightnessGrid.cs index 36af6e0..53970b5 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/BrightnessGrid.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/BrightnessGrid.cs @@ -2,7 +2,7 @@ namespace ServicePoint; -public sealed class BrightnessGrid : SpNativeInstance +public sealed class BrightnessGrid : SpNativeInstance { public static BrightnessGrid New(int width, int height) { @@ -92,12 +92,9 @@ public Span Data } } - 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); } diff --git a/crates/servicepoint_binding_cs/ServicePoint/Command.cs b/crates/servicepoint_binding_cs/ServicePoint/Command.cs index a0349c8..e17c685 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/Command.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/Command.cs @@ -125,8 +125,5 @@ private unsafe Command(BindGen.Command* instance) : base(instance) { } - private protected override unsafe void Dealloc() - { - NativeMethods.sp_command_dealloc(Instance); - } + private protected override unsafe void Free() => NativeMethods.sp_command_free(Instance); } diff --git a/crates/servicepoint_binding_cs/ServicePoint/Connection.cs b/crates/servicepoint_binding_cs/ServicePoint/Connection.cs index 3d1a480..eff3b32 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/Connection.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/Connection.cs @@ -20,15 +20,20 @@ public bool Send(Packet packet) { 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) { } diff --git a/crates/servicepoint_binding_cs/ServicePoint/Cp437Grid.cs b/crates/servicepoint_binding_cs/ServicePoint/Cp437Grid.cs index 01a83fb..905828b 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/Cp437Grid.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/Cp437Grid.cs @@ -3,7 +3,7 @@ namespace ServicePoint; -public sealed class Cp437Grid : SpNativeInstance +public sealed class Cp437Grid : SpNativeInstance { public static Cp437Grid New(int width, int height) { @@ -123,12 +123,9 @@ public Span Data } } - 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); } diff --git a/crates/servicepoint_binding_cs/ServicePoint/Packet.cs b/crates/servicepoint_binding_cs/ServicePoint/Packet.cs index ab4b08a..24c2c18 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/Packet.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/Packet.cs @@ -32,8 +32,5 @@ private unsafe Packet(BindGen.Packet* instance) : base(instance) { } - private protected override unsafe void Dealloc() - { - NativeMethods.sp_packet_dealloc(Instance); - } + private protected override unsafe void Free() => NativeMethods.sp_packet_free(Instance); } diff --git a/crates/servicepoint_binding_cs/ServicePoint/PixelGrid.cs b/crates/servicepoint_binding_cs/ServicePoint/PixelGrid.cs index 1e6fb11..77e0cf3 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/PixelGrid.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/PixelGrid.cs @@ -96,8 +96,5 @@ private unsafe PixelGrid(BindGen.PixelGrid* instance) : base(instance) { } - private protected override unsafe void Dealloc() - { - NativeMethods.sp_pixel_grid_dealloc(Instance); - } + private protected override unsafe void Free() => NativeMethods.sp_pixel_grid_free(Instance); } diff --git a/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj index 6053dc5..b1831d7 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj +++ b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj @@ -11,7 +11,7 @@ ServicePoint - 0.7.0 + 0.8.0 Repository Authors None ServicePoint diff --git a/crates/servicepoint_binding_cs/ServicePoint/SpNativeInstance.cs b/crates/servicepoint_binding_cs/ServicePoint/SpNativeInstance.cs index 23013c8..b6c492e 100644 --- a/crates/servicepoint_binding_cs/ServicePoint/SpNativeInstance.cs +++ b/crates/servicepoint_binding_cs/ServicePoint/SpNativeInstance.cs @@ -22,7 +22,7 @@ private protected unsafe SpNativeInstance(T* instance) _instance = instance; } - private protected abstract void Dealloc(); + private protected abstract void Free(); internal unsafe T* Into() { @@ -34,7 +34,7 @@ private protected unsafe SpNativeInstance(T* instance) private unsafe void ReleaseUnmanagedResources() { if (_instance != null) - Dealloc(); + Free(); _instance = null; } diff --git a/crates/servicepoint_binding_cs/build.rs b/crates/servicepoint_binding_cs/build.rs index ec2744e..5287698 100644 --- a/crates/servicepoint_binding_cs/build.rs +++ b/crates/servicepoint_binding_cs/build.rs @@ -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(); } diff --git a/shell.nix b/shell.nix index 4b4eeca..6da3bc6 100644 --- a/shell.nix +++ b/shell.nix @@ -1,16 +1,24 @@ -{pkgs ? import {}}: -pkgs.mkShell { - nativeBuildInputs = with pkgs.buildPackages; [ - rustc cargo gcc rustfmt clippy +{pkgs ? import {}}: 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}"; + }