a bunch of minor changes combined:
- From instead of Into - unsafe_data_ref for other payloads - CByteSlice for returning memory spans - send Packet instead of Into<Packet> - expose packet layer to C/C#
This commit is contained in:
		
							parent
							
								
									5803b71f3a
								
							
						
					
					
						commit
						1dad113ca1
					
				
					 33 changed files with 462 additions and 733 deletions
				
			
		
							
								
								
									
										11
									
								
								Cargo.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Cargo.toml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| [workspace] | ||||
| resolver = "2" | ||||
| members = [ | ||||
|     "servicepoint2", | ||||
|     "servicepoint2-binding-cs", | ||||
|     "examples/announce", | ||||
|     "examples/game_of_life", | ||||
|     "examples/moving_line", | ||||
|     "examples/wiping_clear", | ||||
|     "examples/random_brightness" | ||||
| ] | ||||
|  | @ -49,6 +49,7 @@ Uses C bindings internally to provide a similar API to rust. Things to keep in m | |||
| - C# specifics are documented in the library. Use the rust documentation for everything else. Naming and semantics are the same apart from CamelCase instead of kebap_case. | ||||
| - You will only get rust backtraces in debug builds of the native code. | ||||
| - F# is not explicitly tested. If there are usability or functionality problems, please open an issue. | ||||
| - Reading and writing to instances concurrently is not safe. Only reading concurrently is safe. | ||||
| 
 | ||||
| ```csharp | ||||
| using ServicePoint2; | ||||
|  | @ -79,6 +80,7 @@ The lowest common denominator. Things to keep in mind: | |||
| - Instances get consumed in the same way they do when writing rust / C# code. Do not use an instance after an (implicit!) free. | ||||
| - Option<T> or Result<T, E> turn into nullable return values - check for NULL! | ||||
| - There are no specifics for C++ here yet. You might get a nicer header when generating directly for C++, but it should be usable. | ||||
| - Reading and writing to instances concurrently is not safe. Only reading concurrently is safe. | ||||
| 
 | ||||
| ```c++ | ||||
| #include <stdio.h> | ||||
|  |  | |||
							
								
								
									
										567
									
								
								examples/Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										567
									
								
								examples/Cargo.lock
									
										
									
										generated
									
									
									
								
							|  | @ -1,567 +0,0 @@ | |||
| # This file is automatically @generated by Cargo. | ||||
| # It is not intended for manual editing. | ||||
| version = 3 | ||||
| 
 | ||||
| [[package]] | ||||
| name = "adler" | ||||
| version = "1.0.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "aho-corasick" | ||||
| version = "1.1.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" | ||||
| dependencies = [ | ||||
|  "memchr", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "announce" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "clap", | ||||
|  "env_logger", | ||||
|  "servicepoint2", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "anstream" | ||||
| version = "0.6.14" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" | ||||
| dependencies = [ | ||||
|  "anstyle", | ||||
|  "anstyle-parse", | ||||
|  "anstyle-query", | ||||
|  "anstyle-wincon", | ||||
|  "colorchoice", | ||||
|  "is_terminal_polyfill", | ||||
|  "utf8parse", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "anstyle" | ||||
| version = "1.0.7" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "anstyle-parse" | ||||
| version = "0.2.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" | ||||
| dependencies = [ | ||||
|  "utf8parse", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "anstyle-query" | ||||
| version = "1.0.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" | ||||
| dependencies = [ | ||||
|  "windows-sys", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "anstyle-wincon" | ||||
| version = "3.0.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" | ||||
| dependencies = [ | ||||
|  "anstyle", | ||||
|  "windows-sys", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "bzip2" | ||||
| version = "0.4.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" | ||||
| dependencies = [ | ||||
|  "bzip2-sys", | ||||
|  "libc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "bzip2-sys" | ||||
| version = "0.1.11+1.0.8" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" | ||||
| dependencies = [ | ||||
|  "cc", | ||||
|  "libc", | ||||
|  "pkg-config", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cc" | ||||
| version = "1.0.97" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" | ||||
| dependencies = [ | ||||
|  "jobserver", | ||||
|  "libc", | ||||
|  "once_cell", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cfg-if" | ||||
| version = "1.0.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "clap" | ||||
| version = "4.5.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" | ||||
| dependencies = [ | ||||
|  "clap_builder", | ||||
|  "clap_derive", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "clap_builder" | ||||
| version = "4.5.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" | ||||
| dependencies = [ | ||||
|  "anstream", | ||||
|  "anstyle", | ||||
|  "clap_lex", | ||||
|  "strsim", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "clap_derive" | ||||
| version = "4.5.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" | ||||
| dependencies = [ | ||||
|  "heck", | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "clap_lex" | ||||
| version = "0.7.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "colorchoice" | ||||
| version = "1.0.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "crc32fast" | ||||
| version = "1.4.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "env_filter" | ||||
| version = "0.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" | ||||
| dependencies = [ | ||||
|  "log", | ||||
|  "regex", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "env_logger" | ||||
| version = "0.11.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" | ||||
| dependencies = [ | ||||
|  "anstream", | ||||
|  "anstyle", | ||||
|  "env_filter", | ||||
|  "humantime", | ||||
|  "log", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "flate2" | ||||
| version = "1.0.30" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" | ||||
| dependencies = [ | ||||
|  "crc32fast", | ||||
|  "miniz_oxide", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "game_of_life" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "clap", | ||||
|  "env_logger", | ||||
|  "rand", | ||||
|  "servicepoint2", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "getrandom" | ||||
| version = "0.2.15" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "libc", | ||||
|  "wasi", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "heck" | ||||
| version = "0.5.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "humantime" | ||||
| version = "2.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "is_terminal_polyfill" | ||||
| version = "1.70.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "jobserver" | ||||
| version = "0.1.31" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "libc" | ||||
| version = "0.2.154" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "log" | ||||
| version = "0.4.21" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "lz4" | ||||
| version = "1.24.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
|  "lz4-sys", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "lz4-sys" | ||||
| version = "1.9.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" | ||||
| dependencies = [ | ||||
|  "cc", | ||||
|  "libc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "memchr" | ||||
| version = "2.7.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "miniz_oxide" | ||||
| version = "0.7.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" | ||||
| dependencies = [ | ||||
|  "adler", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "moving_line" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "clap", | ||||
|  "env_logger", | ||||
|  "servicepoint2", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "once_cell" | ||||
| version = "1.19.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "pkg-config" | ||||
| version = "0.3.30" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "ppv-lite86" | ||||
| version = "0.2.17" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "proc-macro2" | ||||
| version = "1.0.82" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" | ||||
| dependencies = [ | ||||
|  "unicode-ident", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "quote" | ||||
| version = "1.0.36" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rand" | ||||
| version = "0.8.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
|  "rand_chacha", | ||||
|  "rand_core", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rand_chacha" | ||||
| version = "0.3.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" | ||||
| dependencies = [ | ||||
|  "ppv-lite86", | ||||
|  "rand_core", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rand_core" | ||||
| version = "0.6.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" | ||||
| dependencies = [ | ||||
|  "getrandom", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "random_brightness" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "clap", | ||||
|  "env_logger", | ||||
|  "rand", | ||||
|  "servicepoint2", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "regex" | ||||
| version = "1.10.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" | ||||
| dependencies = [ | ||||
|  "aho-corasick", | ||||
|  "memchr", | ||||
|  "regex-automata", | ||||
|  "regex-syntax", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "regex-automata" | ||||
| version = "0.4.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" | ||||
| dependencies = [ | ||||
|  "aho-corasick", | ||||
|  "memchr", | ||||
|  "regex-syntax", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "regex-syntax" | ||||
| version = "0.8.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "servicepoint2" | ||||
| version = "0.2.0" | ||||
| dependencies = [ | ||||
|  "bzip2", | ||||
|  "flate2", | ||||
|  "log", | ||||
|  "lz4", | ||||
|  "zstd", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "strsim" | ||||
| version = "0.11.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "syn" | ||||
| version = "2.0.63" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "unicode-ident", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "unicode-ident" | ||||
| version = "1.0.12" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "utf8parse" | ||||
| version = "0.2.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "wasi" | ||||
| version = "0.11.0+wasi-snapshot-preview1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows-sys" | ||||
| version = "0.52.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" | ||||
| dependencies = [ | ||||
|  "windows-targets", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows-targets" | ||||
| version = "0.52.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" | ||||
| dependencies = [ | ||||
|  "windows_aarch64_gnullvm", | ||||
|  "windows_aarch64_msvc", | ||||
|  "windows_i686_gnu", | ||||
|  "windows_i686_gnullvm", | ||||
|  "windows_i686_msvc", | ||||
|  "windows_x86_64_gnu", | ||||
|  "windows_x86_64_gnullvm", | ||||
|  "windows_x86_64_msvc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_aarch64_gnullvm" | ||||
| version = "0.52.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_aarch64_msvc" | ||||
| version = "0.52.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_i686_gnu" | ||||
| version = "0.52.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_i686_gnullvm" | ||||
| version = "0.52.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_i686_msvc" | ||||
| version = "0.52.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_x86_64_gnu" | ||||
| version = "0.52.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_x86_64_gnullvm" | ||||
| version = "0.52.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_x86_64_msvc" | ||||
| version = "0.52.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "wiping_clear" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "clap", | ||||
|  "env_logger", | ||||
|  "servicepoint2", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "zstd" | ||||
| version = "0.13.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" | ||||
| dependencies = [ | ||||
|  "zstd-safe", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "zstd-safe" | ||||
| version = "7.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" | ||||
| dependencies = [ | ||||
|  "zstd-sys", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "zstd-sys" | ||||
| version = "2.0.10+zstd.1.5.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" | ||||
| dependencies = [ | ||||
|  "cc", | ||||
|  "pkg-config", | ||||
| ] | ||||
|  | @ -1,9 +0,0 @@ | |||
| [workspace] | ||||
| resolver = "2" | ||||
| members = [ | ||||
|     "announce", | ||||
|     "game_of_life", | ||||
|     "moving_line", | ||||
|     "wiping_clear", | ||||
|     "random_brightness" | ||||
| ] | ||||
|  | @ -20,7 +20,7 @@ fn main() { | |||
| 
 | ||||
|     let connection = Connection::open(&cli.destination).unwrap(); | ||||
|     if cli.clear { | ||||
|         connection.send(Command::Clear).unwrap(); | ||||
|         connection.send(Command::Clear.into()).unwrap(); | ||||
|     } | ||||
| 
 | ||||
|     let mut max_width = 0; | ||||
|  | @ -43,6 +43,6 @@ fn main() { | |||
|     } | ||||
| 
 | ||||
|     connection | ||||
|         .send(Command::Cp437Data(Origin::top_left(), chars)) | ||||
|         .send(Command::Cp437Data(Origin::top_left(), chars).into()) | ||||
|         .unwrap(); | ||||
| } | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ fn main() { | |||
| 
 | ||||
|     loop { | ||||
|         connection | ||||
|             .send(Command::BitmapLinearWin(Origin::top_left(), field.clone())) | ||||
|             .send(Command::BitmapLinearWin(Origin::top_left(), field.clone()).into()) | ||||
|             .expect("could not send"); | ||||
|         thread::sleep(Duration::from_millis(14)); | ||||
|         field = iteration(field); | ||||
|  |  | |||
|  | @ -3,11 +3,11 @@ OUT_DIR := ${ROOT_DIR}/out | |||
| 
 | ||||
| SP2_DIR := ${ROOT_DIR}/../../servicepoint2 | ||||
| SP2_INCLUDE := ${ROOT_DIR}/../../servicepoint2-binding-c | ||||
| SP2_TARGET_RELEASE := ${ROOT_DIR}/../../target/release | ||||
| SP2_TARGET_RELEASE := ${SP2_DIR}/target/release | ||||
| 
 | ||||
| .PHONY: build run clean | ||||
| 
 | ||||
| build: ${OUT_DIR}/lang_c | ||||
| all: ${OUT_DIR}/lang_c | ||||
| 
 | ||||
| run: ${OUT_DIR}/lang_c | ||||
| 	out/lang_c | ||||
|  |  | |||
|  | @ -8,11 +8,11 @@ int main(void) { | |||
| 
 | ||||
|     sp2_PixelGrid *pixels = sp2_pixel_grid_new(sp2_PIXEL_WIDTH, sp2_PIXEL_HEIGHT); | ||||
|     sp2_pixel_grid_fill(pixels, true); | ||||
| 
 | ||||
|     sp2_Command *command = sp2_command_bitmap_linear_win(0, 0, pixels); | ||||
|     if (command == NULL) | ||||
|         return 4; | ||||
|     if (!sp2_connection_send(connection, command)) | ||||
|         return 5; | ||||
|     sp2_Packet *packet = sp2_packet_from_command(command); | ||||
|     if (!sp2_connection_send(connection, packet)) | ||||
|         return 1; | ||||
| 
 | ||||
|     sp2_connection_dealloc(connection); | ||||
|     return 0; | ||||
|  |  | |||
|  | @ -2,8 +2,8 @@ | |||
| 
 | ||||
| using var connection = Connection.Open("127.0.0.1:2342"); | ||||
| 
 | ||||
| connection.Send(Command.Clear()); | ||||
| connection.Send(Command.Brightness(128)); | ||||
| connection.Send(Command.Clear().IntoPacket()); | ||||
| connection.Send(Command.Brightness(128).IntoPacket()); | ||||
| 
 | ||||
| using var pixels = PixelGrid.New(Constants.PixelWidth, Constants.PixelHeight); | ||||
| 
 | ||||
|  | @ -14,6 +14,6 @@ for (var offset = 0; offset < int.MaxValue; offset++) | |||
|     for (var y = 0; y < pixels.Height; y++) | ||||
|         pixels[(y + offset) % Constants.PixelWidth, y] = true; | ||||
| 
 | ||||
|     connection.Send(Command.BitmapLinearWin(0, 0, pixels.Clone())); | ||||
|     connection.Send(Command.BitmapLinearWin(0, 0, pixels.Clone()).IntoPacket()); | ||||
|     Thread.Sleep(14); | ||||
| } | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ fn main() { | |||
|             pixels.set((y + x_offset) % PIXEL_WIDTH as usize, y, true); | ||||
|         } | ||||
|         connection | ||||
|             .send(Command::BitmapLinearWin(Origin::top_left(), pixels.clone())) | ||||
|             .send(Command::BitmapLinearWin(Origin::top_left(), pixels.clone()).into()) | ||||
|             .unwrap(); | ||||
|         thread::sleep(Duration::from_millis(14)); | ||||
|     } | ||||
|  |  | |||
|  | @ -30,13 +30,13 @@ fn main() { | |||
|         let mut filled_grid = PixelGrid::max_sized(); | ||||
|         filled_grid.fill(true); | ||||
|         connection | ||||
|             .send(BitmapLinearWin(Origin::top_left(), filled_grid)) | ||||
|             .send(BitmapLinearWin(Origin::top_left(), filled_grid).into()) | ||||
|             .unwrap(); | ||||
|     } | ||||
| 
 | ||||
|     // set all pixels to the same random brightness
 | ||||
|     let mut rng = rand::thread_rng(); | ||||
|     connection.send(Brightness(rng.gen())).unwrap(); | ||||
|     connection.send(Brightness(rng.gen()).into()).unwrap(); | ||||
| 
 | ||||
|     // continuously update random windows to new random brightness
 | ||||
|     loop { | ||||
|  | @ -56,7 +56,7 @@ fn main() { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         connection.send(CharBrightness(origin, luma)).unwrap(); | ||||
|         connection.send(CharBrightness(origin, luma).into()).unwrap(); | ||||
|         std::thread::sleep(wait_duration); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ fn main() { | |||
|         let bit_vec = BitVec::from(&*pixel_data); | ||||
| 
 | ||||
|         connection | ||||
|             .send(Command::BitmapLinearAnd(0, bit_vec, CompressionCode::Gz)) | ||||
|             .send(Command::BitmapLinearAnd(0, bit_vec, CompressionCode::Gz).into()) | ||||
|             .unwrap(); | ||||
|         thread::sleep(sleep_duration); | ||||
|     } | ||||
|  |  | |||
|  | @ -68,7 +68,7 @@ typedef uint16_t sp2_CompressionCode; | |||
| typedef struct sp2_BitVec sp2_BitVec; | ||||
| 
 | ||||
| /**
 | ||||
|  * A grid of bytes | ||||
|  * A 2D grid of bytes | ||||
|  */ | ||||
| typedef struct sp2_ByteGrid sp2_ByteGrid; | ||||
| 
 | ||||
|  | @ -82,13 +82,40 @@ typedef struct sp2_Command sp2_Command; | |||
|  */ | ||||
| typedef struct sp2_Connection sp2_Connection; | ||||
| 
 | ||||
| /**
 | ||||
|  * The raw packet. Should probably not be used directly. | ||||
|  */ | ||||
| typedef struct sp2_Packet sp2_Packet; | ||||
| 
 | ||||
| /**
 | ||||
|  * A grid of pixels stored in packed bytes. | ||||
|  */ | ||||
| typedef struct sp2_PixelGrid sp2_PixelGrid; | ||||
| 
 | ||||
| /**
 | ||||
|  * Represents a `&mut [u8]` as a struct usable by C code. | ||||
|  * | ||||
|  * Usage of this type is inherently unsafe. | ||||
|  */ | ||||
| typedef struct sp2_CByteSlice { | ||||
|     /**
 | ||||
|      * The start address of the memory | ||||
|      */ | ||||
|     uint8_t *start; | ||||
|     /**
 | ||||
|      * The amount of memory in bytes | ||||
|      */ | ||||
|     size_t length; | ||||
| } sp2_CByteSlice; | ||||
| 
 | ||||
| /**
 | ||||
|  * Type alias for documenting the meaning of the u16 in enum values | ||||
|  */ | ||||
| typedef uint16_t sp2_Offset; | ||||
| 
 | ||||
| /**
 | ||||
|  * Type alias for documenting the meaning of the u16 in enum values | ||||
|  */ | ||||
| typedef uint8_t sp2_Brightness; | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
|  | @ -140,6 +167,19 @@ struct sp2_BitVec *sp2_bit_vec_new(size_t size); | |||
|  */ | ||||
| bool sp2_bit_vec_set(struct sp2_BitVec *this_, size_t index, bool value); | ||||
| 
 | ||||
| /**
 | ||||
|  * Gets an unsafe reference to the data of the `BitVec` instance. | ||||
|  * | ||||
|  * ## Safety | ||||
|  * | ||||
|  * The caller has to make sure to never access the returned memory after the `BitVec` | ||||
|  * instance has been consumed or manually deallocated. | ||||
|  * | ||||
|  * Reading and writing concurrently to either the original instance or the returned data will | ||||
|  * result in undefined behavior. | ||||
|  */ | ||||
| struct sp2_CByteSlice sp2_bit_vec_unsafe_data_ref(struct sp2_BitVec *this_); | ||||
| 
 | ||||
| /**
 | ||||
|  * Clones a `ByteGrid`. | ||||
|  * The returned instance has to be freed with `byte_grid_dealloc`. | ||||
|  | @ -166,7 +206,7 @@ uint8_t sp2_byte_grid_get(const struct sp2_ByteGrid *this_, size_t x, size_t y); | |||
| /**
 | ||||
|  * Gets the height in pixels of the `ByteGrid` instance. | ||||
|  */ | ||||
| size_t sp2_byte_grid_height(const struct sp2_PixelGrid *this_); | ||||
| size_t sp2_byte_grid_height(const struct sp2_ByteGrid *this_); | ||||
| 
 | ||||
| /**
 | ||||
|  * Loads a `ByteGrid` with the specified dimensions from the provided data. | ||||
|  | @ -191,10 +231,23 @@ void sp2_byte_grid_set(struct sp2_ByteGrid *this_, | |||
|                        size_t y, | ||||
|                        uint8_t value); | ||||
| 
 | ||||
| /**
 | ||||
|  * Gets an unsafe reference to the data of the `ByteGrid` instance. | ||||
|  * | ||||
|  * ## Safety | ||||
|  * | ||||
|  * The caller has to make sure to never access the returned memory after the `ByteGrid` | ||||
|  * instance has been consumed or manually deallocated. | ||||
|  * | ||||
|  * Reading and writing concurrently to either the original instance or the returned data will | ||||
|  * result in undefined behavior. | ||||
|  */ | ||||
| struct sp2_CByteSlice sp2_byte_grid_unsafe_data_ref(struct sp2_ByteGrid *this_); | ||||
| 
 | ||||
| /**
 | ||||
|  * Gets the width in pixels of the `ByteGrid` instance. | ||||
|  */ | ||||
| size_t sp2_byte_grid_width(const struct sp2_PixelGrid *this_); | ||||
| size_t sp2_byte_grid_width(const struct sp2_ByteGrid *this_); | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocates a new `Command::BitmapLinear` instance. | ||||
|  | @ -283,6 +336,13 @@ struct sp2_Command *sp2_command_fade_out(void); | |||
|  */ | ||||
| struct sp2_Command *sp2_command_hard_reset(void); | ||||
| 
 | ||||
| /**
 | ||||
|  * Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process. | ||||
|  * | ||||
|  * Returns: pointer to command or NULL | ||||
|  */ | ||||
| struct sp2_Command *sp2_command_try_from_packet(struct sp2_Packet *packet); | ||||
| 
 | ||||
| /**
 | ||||
|  * Tries to load a `Command` from the passed array with the specified length. | ||||
|  * | ||||
|  | @ -309,7 +369,12 @@ struct sp2_Connection *sp2_connection_open(const char *host); | |||
|  * Sends the command instance. The instance is consumed / destroyed and cannot be used after this call. | ||||
|  */ | ||||
| bool sp2_connection_send(const struct sp2_Connection *connection, | ||||
|                          struct sp2_Command *command_ptr); | ||||
|                          struct sp2_Packet *command_ptr); | ||||
| 
 | ||||
| /**
 | ||||
|  * Turns a `Command` into a `Packet`. The command gets deallocated in the process. | ||||
|  */ | ||||
| struct sp2_Packet *sp2_packet_from_command(struct sp2_Command *command); | ||||
| 
 | ||||
| /**
 | ||||
|  * Clones a `PixelGrid`. | ||||
|  | @ -362,6 +427,19 @@ void sp2_pixel_grid_set(struct sp2_PixelGrid *this_, | |||
|                         size_t y, | ||||
|                         bool value); | ||||
| 
 | ||||
| /**
 | ||||
|  * Gets an unsafe reference to the data of the `PixelGrid` instance. | ||||
|  * | ||||
|  * ## Safety | ||||
|  * | ||||
|  * The caller has to make sure to never access the returned memory after the `PixelGrid` | ||||
|  * instance has been consumed or manually deallocated. | ||||
|  * | ||||
|  * Reading and writing concurrently to either the original instance or the returned data will | ||||
|  * result in undefined behavior. | ||||
|  */ | ||||
| struct sp2_CByteSlice sp2_pixel_grid_unsafe_data_ref(struct sp2_PixelGrid *this_); | ||||
| 
 | ||||
| /**
 | ||||
|  * Gets the width in pixels of the `PixelGrid` instance. | ||||
|  */ | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ fn main() { | |||
|         .input_extern_file("../servicepoint2/src/connection.rs") | ||||
|         .input_extern_file("../servicepoint2/src/pixel_grid.rs") | ||||
|         .input_extern_file("../servicepoint2/src/lib.rs") | ||||
|         .input_extern_file("../servicepoint2/src/c_slice.rs") | ||||
|         .input_extern_file("../servicepoint2/src/packet.rs") | ||||
|         .csharp_dll_name("servicepoint2") | ||||
|         .csharp_namespace("ServicePoint2.BindGen") | ||||
|         .csharp_use_nint_types(true) | ||||
|  |  | |||
|  | @ -50,6 +50,10 @@ namespace ServicePoint2.BindGen | |||
|         [DllImport(__DllName, EntryPoint = "sp2_bit_vec_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern nuint sp2_bit_vec_len(BitVec* @this); | ||||
| 
 | ||||
|         /// <summary>Gets an unsafe reference to the data of the `BitVec` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `BitVec` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern CByteSlice sp2_bit_vec_unsafe_data_ref(BitVec* @this); | ||||
| 
 | ||||
|         /// <summary>Creates a new `ByteGrid` instance. The returned instance has to be freed with `byte_grid_dealloc`.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_byte_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern ByteGrid* sp2_byte_grid_new(nuint width, nuint height); | ||||
|  | @ -86,9 +90,13 @@ namespace ServicePoint2.BindGen | |||
|         [DllImport(__DllName, EntryPoint = "sp2_byte_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern nuint sp2_byte_grid_height(ByteGrid* @this); | ||||
| 
 | ||||
|         /// <summary>Tries to load a `Command` from the passed array with the specified length.  returns: NULL in case of an error, pointer to the allocated command otherwise</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_command_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Command* sp2_command_try_load(byte* data, nuint length); | ||||
|         /// <summary>Gets an unsafe reference to the data of the `ByteGrid` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `ByteGrid` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_byte_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern CByteSlice sp2_byte_grid_unsafe_data_ref(ByteGrid* @this); | ||||
| 
 | ||||
|         /// <summary>Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.  Returns: pointer to command or NULL</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Command* sp2_command_try_from_packet(Packet* packet); | ||||
| 
 | ||||
|         /// <summary>Clones a `Command` instance</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_command_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|  | @ -149,7 +157,7 @@ namespace ServicePoint2.BindGen | |||
|         /// <summary>Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_connection_send", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         [return: MarshalAs(UnmanagedType.U1)] | ||||
|         public static extern bool sp2_connection_send(Connection* connection, Command* command_ptr); | ||||
|         public static extern bool sp2_connection_send(Connection* connection, Packet* command_ptr); | ||||
| 
 | ||||
|         /// <summary>Closes and deallocates a connection instance</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_connection_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|  | @ -192,9 +200,21 @@ namespace ServicePoint2.BindGen | |||
|         [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern nuint sp2_pixel_grid_height(PixelGrid* @this); | ||||
| 
 | ||||
|         /// <summary>Gets a reference to the data of the `PixelGrid` instance.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern byte* sp2_pixel_grid_data_ref(PixelGrid* @this); | ||||
|         /// <summary>Gets an unsafe reference to the data of the `PixelGrid` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `PixelGrid` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern CByteSlice sp2_pixel_grid_unsafe_data_ref(PixelGrid* @this); | ||||
| 
 | ||||
|         /// <summary>Turns a `Command` into a `Packet`. The command gets deallocated in the process.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_packet_from_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Packet* sp2_packet_from_command(Command* command); | ||||
| 
 | ||||
|         /// <summary>Tries to load a `Packet` from the passed array with the specified length.  returns: NULL in case of an error, pointer to the allocated packet otherwise</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_packet_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Packet* sp2_packet_try_load(byte* data, nuint length); | ||||
| 
 | ||||
|         /// <summary>Deallocates a `Packet`.  Note: do not call this if the instance has been consumed in another way, e.g. by sending it.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_packet_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern void sp2_packet_dealloc(Packet* @this); | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
|  | @ -219,6 +239,18 @@ namespace ServicePoint2.BindGen | |||
|     { | ||||
|     } | ||||
| 
 | ||||
|     [StructLayout(LayoutKind.Sequential)] | ||||
|     public unsafe partial struct CByteSlice | ||||
|     { | ||||
|         public byte* start; | ||||
|         public nuint length; | ||||
|     } | ||||
| 
 | ||||
|     [StructLayout(LayoutKind.Sequential)] | ||||
|     public unsafe partial struct Packet | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public enum Command | ||||
|     { | ||||
|  |  | |||
|  | @ -68,11 +68,23 @@ public sealed class BitVec : Sp2NativeInstance<BindGen.BitVec> | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public Span<byte> Data | ||||
|     { | ||||
|         get | ||||
|         { | ||||
|             unsafe | ||||
|             { | ||||
|                 var slice = NativeMethods.sp2_bit_vec_unsafe_data_ref(Instance); | ||||
|                 return new Span<byte>(slice.start, (int)slice.length); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private unsafe BitVec(BindGen.BitVec* instance) : base(instance) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     protected override unsafe void Dealloc() | ||||
|     private protected override unsafe void Dealloc() | ||||
|     { | ||||
|         NativeMethods.sp2_bit_vec_dealloc(Instance); | ||||
|     } | ||||
|  |  | |||
|  | @ -111,11 +111,23 @@ public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid> | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public Span<byte> Data | ||||
|     { | ||||
|         get | ||||
|         { | ||||
|             unsafe | ||||
|             { | ||||
|                 var slice = NativeMethods.sp2_byte_grid_unsafe_data_ref(Instance); | ||||
|                 return new Span<byte>(slice.start, (int)slice.length); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private unsafe ByteGrid(BindGen.ByteGrid* instance) : base(instance) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     protected override unsafe void Dealloc() | ||||
|     private protected override unsafe void Dealloc() | ||||
|     { | ||||
|         NativeMethods.sp2_byte_grid_dealloc(Instance); | ||||
|     } | ||||
|  |  | |||
|  | @ -5,6 +5,22 @@ namespace ServicePoint2; | |||
| 
 | ||||
| public sealed class Command : Sp2NativeInstance<BindGen.Command> | ||||
| { | ||||
|     public static bool TryFromPacket(Packet packet, [MaybeNullWhen(false)] out Command command) | ||||
|     { | ||||
|         unsafe | ||||
|         { | ||||
|             var result = NativeMethods.sp2_command_try_from_packet(packet.Into()); | ||||
|             if (result == null) | ||||
|             { | ||||
|                 command = null; | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             command = new Command(result); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public Command Clone() | ||||
|     { | ||||
|         unsafe | ||||
|  | @ -13,21 +29,6 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command> | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static bool TryLoad(Span<byte> bytes, [MaybeNullWhen(false)] out Command command) | ||||
|     { | ||||
|         unsafe | ||||
|         { | ||||
|             fixed (byte* bytesPtr = bytes) | ||||
|             { | ||||
|                 var instance = NativeMethods.sp2_command_try_load(bytesPtr, (nuint)bytes.Length); | ||||
|                 command = instance == null | ||||
|                     ? null | ||||
|                     : new Command(instance); | ||||
|                 return command != null; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static Command Clear() | ||||
|     { | ||||
|         unsafe | ||||
|  | @ -124,7 +125,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command> | |||
|     { | ||||
|     } | ||||
| 
 | ||||
|     protected override unsafe void Dealloc() | ||||
|     private protected override unsafe void Dealloc() | ||||
|     { | ||||
|         NativeMethods.sp2_command_dealloc(Instance); | ||||
|     } | ||||
|  |  | |||
|  | @ -16,15 +16,15 @@ public sealed class Connection : Sp2NativeInstance<BindGen.Connection> | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public bool Send(Command command) | ||||
|     public bool Send(Packet packet) | ||||
|     { | ||||
|         unsafe | ||||
|         { | ||||
|             return NativeMethods.sp2_connection_send(Instance, command.Into()); | ||||
|             return NativeMethods.sp2_connection_send(Instance, packet.Into()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     protected override unsafe void Dealloc() | ||||
|     private protected override unsafe void Dealloc() | ||||
|     { | ||||
|         NativeMethods.sp2_connection_dealloc(Instance); | ||||
|     } | ||||
|  |  | |||
							
								
								
									
										39
									
								
								servicepoint2-binding-cs/src/Packet.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								servicepoint2-binding-cs/src/Packet.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | |||
| using System.Diagnostics.CodeAnalysis; | ||||
| using ServicePoint2.BindGen; | ||||
| 
 | ||||
| namespace ServicePoint2; | ||||
| 
 | ||||
| public sealed class Packet : Sp2NativeInstance<BindGen.Packet> | ||||
| { | ||||
|     public static Packet FromCommand(Command command) | ||||
|     { | ||||
|         unsafe | ||||
|         { | ||||
|             return new Packet(NativeMethods.sp2_packet_from_command(command.Into())); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static bool TryFromBytes(Span<byte> bytes, [MaybeNullWhen(false)] out Packet packet) | ||||
|     { | ||||
|         unsafe | ||||
|         { | ||||
|             fixed (byte* bytesPtr = bytes) | ||||
|             { | ||||
|                 var instance = NativeMethods.sp2_packet_try_load(bytesPtr, (nuint)bytes.Length); | ||||
|                 packet = instance == null | ||||
|                     ? null | ||||
|                     : new Packet(instance); | ||||
|                 return packet != null; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private unsafe Packet(BindGen.Packet* instance) : base(instance) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     private protected override unsafe void Dealloc() | ||||
|     { | ||||
|         NativeMethods.sp2_packet_dealloc(Instance); | ||||
|     } | ||||
| } | ||||
|  | @ -86,8 +86,8 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid> | |||
|         { | ||||
|             unsafe | ||||
|             { | ||||
|                 var ptr = NativeMethods.sp2_pixel_grid_data_ref(Instance); | ||||
|                 return new Span<byte>(ptr, Width * Height / 8); | ||||
|                 var slice = NativeMethods.sp2_pixel_grid_unsafe_data_ref(Instance); | ||||
|                 return new Span<byte>(slice.start, (int)slice.length); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | @ -96,7 +96,7 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid> | |||
|     { | ||||
|     } | ||||
| 
 | ||||
|     protected override unsafe void Dealloc() | ||||
|     private protected override unsafe void Dealloc() | ||||
|     { | ||||
|         NativeMethods.sp2_pixel_grid_dealloc(Instance); | ||||
|     } | ||||
|  |  | |||
							
								
								
									
										16
									
								
								servicepoint2-binding-cs/src/ServicePoint2Extensions.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								servicepoint2-binding-cs/src/ServicePoint2Extensions.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| using System.Diagnostics.CodeAnalysis; | ||||
| 
 | ||||
| namespace ServicePoint2; | ||||
| 
 | ||||
| public static class ServicePoint2Extensions | ||||
| { | ||||
|     public static Packet IntoPacket(this Command command) | ||||
|     { | ||||
|         return Packet.FromCommand(command); | ||||
|     } | ||||
| 
 | ||||
|     public static bool TryIntoCommand(this Packet packet, [MaybeNullWhen(false)] out Command command) | ||||
|     { | ||||
|         return Command.TryFromPacket(packet, out command); | ||||
|     } | ||||
| } | ||||
|  | @ -22,7 +22,7 @@ public abstract class Sp2NativeInstance<T> | |||
|         _instance = instance; | ||||
|     } | ||||
| 
 | ||||
|     protected abstract void Dealloc(); | ||||
|     private protected abstract void Dealloc(); | ||||
| 
 | ||||
|     internal unsafe T* Into() | ||||
|     { | ||||
|  |  | |||
|  | @ -71,14 +71,17 @@ impl BitVec { | |||
|         self.data.fill(byte); | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the length in bits
 | ||||
|     pub fn len(&self) -> usize { | ||||
|         self.data.len() * 8 | ||||
|     } | ||||
| 
 | ||||
|     pub fn data_ref(&self) -> &[u8] { | ||||
|         &*self.data | ||||
|     /// Get the underlying bits in their raw packed bytes form
 | ||||
|     pub fn mut_data_ref(&mut self) -> &mut [u8] { | ||||
|         self.data.as_mut_slice() | ||||
|     } | ||||
| 
 | ||||
|     /// Calculates the byte index and bitmask for a specific bit in the vector
 | ||||
|     fn get_indexes(&self, index: usize) -> (usize, u8) { | ||||
|         let byte_index = index / 8; | ||||
|         let bit_in_byte_index = 7 - index % 8; | ||||
|  | @ -87,13 +90,15 @@ impl BitVec { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Into<Vec<u8>> for BitVec { | ||||
|     fn into(self) -> Vec<u8> { | ||||
|         self.data | ||||
| impl From<BitVec> for Vec<u8> { | ||||
|     /// Turns the `BitVec` into the underlying `Vec<u8>`
 | ||||
|     fn from(value: BitVec) -> Self { | ||||
|         value.data | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<&[u8]> for BitVec { | ||||
|     /// Interpret the data as a series of bits and load then into a new `BitVec` instance.
 | ||||
|     fn from(value: &[u8]) -> Self { | ||||
|         Self { | ||||
|             data: Vec::from(value), | ||||
|  | @ -102,6 +107,7 @@ impl From<&[u8]> for BitVec { | |||
| } | ||||
| 
 | ||||
| impl std::fmt::Debug for BitVec { | ||||
|     /// Formats a `BitVec` for debug. The manual implementation includes the length of the instance.
 | ||||
|     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         fmt.debug_struct("BitVec") | ||||
|             .field("len", &self.len()) | ||||
|  | @ -112,7 +118,7 @@ impl std::fmt::Debug for BitVec { | |||
| 
 | ||||
| #[cfg(feature = "c-api")] | ||||
| pub mod c_api { | ||||
|     use crate::BitVec; | ||||
|     use crate::{BitVec, CByteSlice}; | ||||
| 
 | ||||
|     /// Creates a new `BitVec` instance.
 | ||||
|     /// The returned instance has to be freed with `bit_vec_dealloc`.
 | ||||
|  | @ -167,4 +173,22 @@ pub mod c_api { | |||
|     pub unsafe extern "C" fn sp2_bit_vec_len(this: *const BitVec) -> usize { | ||||
|         (*this).len() | ||||
|     } | ||||
| 
 | ||||
|     /// Gets an unsafe reference to the data of the `BitVec` instance.
 | ||||
|     ///
 | ||||
|     /// ## Safety
 | ||||
|     ///
 | ||||
|     /// The caller has to make sure to never access the returned memory after the `BitVec`
 | ||||
|     /// instance has been consumed or manually deallocated.
 | ||||
|     ///
 | ||||
|     /// Reading and writing concurrently to either the original instance or the returned data will
 | ||||
|     /// result in undefined behavior.
 | ||||
|     #[no_mangle] | ||||
|     pub unsafe extern "C" fn sp2_bit_vec_unsafe_data_ref(this: *mut BitVec) -> CByteSlice { | ||||
|         let data = (*this).mut_data_ref(); | ||||
|         CByteSlice { | ||||
|             start: data.as_mut_ptr_range().start, | ||||
|             length: data.len(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,9 @@ | |||
| /// A grid of bytes
 | ||||
| /// A 2D grid of bytes
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct ByteGrid { | ||||
|     /// Size in the x-axis
 | ||||
|     pub width: usize, | ||||
|     /// Size in the y-axis
 | ||||
|     pub height: usize, | ||||
|     data: Vec<u8>, | ||||
| } | ||||
|  | @ -50,18 +52,24 @@ impl ByteGrid { | |||
|     pub fn fill(&mut self, value: u8) { | ||||
|         self.data.fill(value) | ||||
|     } | ||||
| 
 | ||||
|     /// Get the underlying byte rows
 | ||||
|     pub fn mut_data_ref(&mut self) -> &mut [u8] { | ||||
|         self.data.as_mut_slice() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Into<Vec<u8>> for ByteGrid { | ||||
|     fn into(self) -> Vec<u8> { | ||||
|         self.data | ||||
| impl From<ByteGrid> for Vec<u8> { | ||||
|     /// Turn into the underlying `Vec<u8>` containing the rows of bytes.
 | ||||
|     fn from(value: ByteGrid) -> Self { | ||||
|         value.data | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(feature = "c-api")] | ||||
| pub mod c_api | ||||
| { | ||||
|     use crate::ByteGrid; | ||||
|     use crate::{ByteGrid, CByteSlice}; | ||||
| 
 | ||||
|     /// Creates a new `ByteGrid` instance.
 | ||||
|     /// The returned instance has to be freed with `byte_grid_dealloc`.
 | ||||
|  | @ -122,4 +130,22 @@ pub mod c_api | |||
|     pub unsafe extern "C" fn sp2_byte_grid_height(this: *const ByteGrid) -> usize { | ||||
|         (*this).height | ||||
|     } | ||||
| 
 | ||||
|     /// Gets an unsafe reference to the data of the `ByteGrid` instance.
 | ||||
|     ///
 | ||||
|     /// ## Safety
 | ||||
|     ///
 | ||||
|     /// The caller has to make sure to never access the returned memory after the `ByteGrid`
 | ||||
|     /// instance has been consumed or manually deallocated.
 | ||||
|     ///
 | ||||
|     /// Reading and writing concurrently to either the original instance or the returned data will
 | ||||
|     /// result in undefined behavior.
 | ||||
|     #[no_mangle] | ||||
|     pub unsafe extern "C" fn sp2_byte_grid_unsafe_data_ref(this: *mut ByteGrid) -> CByteSlice { | ||||
|         let data = (*this).mut_data_ref(); | ||||
|         CByteSlice { | ||||
|             start: data.as_mut_ptr_range().start, | ||||
|             length: data.len(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								servicepoint2/src/c_slice.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								servicepoint2/src/c_slice.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| #[cfg(feature = "c-api")] | ||||
| #[repr(C)] | ||||
| /// Represents a span of memory (`&mut [u8]` ) as a struct usable by C code.
 | ||||
| ///
 | ||||
| /// Usage of this type is inherently unsafe.
 | ||||
| pub struct CByteSlice { | ||||
|     /// The start address of the memory
 | ||||
|     pub start: *mut u8, | ||||
|     /// The amount of memory in bytes
 | ||||
|     pub length: usize, | ||||
| } | ||||
|  | @ -1,7 +1,8 @@ | |||
| use crate::{ | ||||
|     BitVec, ByteGrid, CommandCode, CompressionCode, Header, Packet, PixelGrid, | ||||
|     BitVec, ByteGrid, CompressionCode, Header, Packet, PixelGrid, | ||||
|     TILE_SIZE, | ||||
| }; | ||||
| use crate::command_code::CommandCode; | ||||
| use crate::compression::{into_compressed, into_decompressed}; | ||||
| 
 | ||||
| /// An origin marks the top left position of a window sent to the display.
 | ||||
|  | @ -18,8 +19,10 @@ impl Origin { | |||
| #[derive(Debug, Clone, Copy)] | ||||
| pub struct Size(pub u16, pub u16); | ||||
| 
 | ||||
| /// Type alias for documenting the meaning of the u16 in enum values
 | ||||
| pub type Offset = u16; | ||||
| 
 | ||||
| /// Type alias for documenting the meaning of the u16 in enum values
 | ||||
| pub type Brightness = u8; | ||||
| 
 | ||||
| /// A command to send to the display.
 | ||||
|  | @ -29,12 +32,14 @@ pub enum Command { | |||
|     Clear, | ||||
|     /// Kills the udp daemon, usually results in a reboot of the display.
 | ||||
|     HardReset, | ||||
|     /// Slowly decrease brightness until off? Untested.
 | ||||
|     FadeOut, | ||||
|     /// Set the brightness of tiles
 | ||||
|     CharBrightness(Origin, ByteGrid), | ||||
|     /// Set the brightness of all tiles
 | ||||
|     Brightness(Brightness), | ||||
|     #[deprecated] | ||||
|     /// Legacy command code, gets ignored by the real display.
 | ||||
|     BitmapLegacy, | ||||
|     /// Set pixel data starting at the offset.
 | ||||
|     /// The contained BitVec is always uncompressed.
 | ||||
|  | @ -54,9 +59,10 @@ pub enum Command { | |||
|     BitmapLinearWin(Origin, PixelGrid), | ||||
| } | ||||
| 
 | ||||
| impl Into<Packet> for Command { | ||||
|     fn into(self) -> Packet { | ||||
|         match self { | ||||
| impl From<Command> for Packet { | ||||
|     /// Move the `Command` into a `Packet` instance for sending.
 | ||||
|     fn from(value: Command) -> Self { | ||||
|         match value { | ||||
|             Command::Clear => command_code_only(CommandCode::Clear), | ||||
|             Command::FadeOut => command_code_only(CommandCode::FadeOut), | ||||
|             Command::HardReset => command_code_only(CommandCode::HardReset), | ||||
|  | @ -64,10 +70,9 @@ impl Into<Packet> for Command { | |||
|             Command::BitmapLegacy => { | ||||
|                 command_code_only(CommandCode::BitmapLegacy) | ||||
|             } | ||||
|             Command::CharBrightness(origin, grid) => origin_size_payload( | ||||
|                 CommandCode::CharBrightness, | ||||
|                 origin, | ||||
|                 Size(grid.width as u16, grid.height as u16), | ||||
|             Command::CharBrightness(Origin(x, y), grid) => Packet( | ||||
|                 Header(CommandCode::CharBrightness.into(), | ||||
|                        x, y, grid.width as u16, grid.height as u16), | ||||
|                 grid.into(), | ||||
|             ), | ||||
|             Command::Brightness(brightness) => Packet( | ||||
|  | @ -126,10 +131,8 @@ impl Into<Packet> for Command { | |||
|                     bits.into(), | ||||
|                 ) | ||||
|             } | ||||
|             Command::Cp437Data(origin, grid) => origin_size_payload( | ||||
|                 CommandCode::Cp437Data, | ||||
|                 origin, | ||||
|                 Size(grid.width as u16, grid.height as u16), | ||||
|             Command::Cp437Data(Origin(x, y), grid) => Packet( | ||||
|                 Header(CommandCode::Cp437Data.into(), x, y, grid.width as u16, grid.height as u16), | ||||
|                 grid.into(), | ||||
|             ), | ||||
|         } | ||||
|  | @ -137,6 +140,7 @@ impl Into<Packet> for Command { | |||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| /// Err values for `Command::try_from`.
 | ||||
| pub enum TryFromPacketError { | ||||
|     /// the contained command code does not correspond to a known command
 | ||||
|     InvalidCommand(u16), | ||||
|  | @ -155,6 +159,7 @@ pub enum TryFromPacketError { | |||
| impl TryFrom<Packet> for Command { | ||||
|     type Error = TryFromPacketError; | ||||
| 
 | ||||
|     /// Try to interpret the `Packet` as one containing a `Command`
 | ||||
|     fn try_from(value: Packet) -> Result<Self, Self::Error> { | ||||
|         let Packet(Header(command_u16, a, b, c, d), _) = value; | ||||
|         let command_code = match CommandCode::try_from(command_u16) { | ||||
|  | @ -178,9 +183,11 @@ impl TryFrom<Packet> for Command { | |||
|                     )); | ||||
|                 } | ||||
| 
 | ||||
|                 match check_empty_header(header) { | ||||
|                     Some(err) => Err(err), | ||||
|                     None => Ok(Command::Brightness(payload[0])), | ||||
|                 let Header(_, a, b, c, d) = header; | ||||
|                 if a != 0 || b != 0 || c != 0 || d != 0 { | ||||
|                     Err(TryFromPacketError::ExtraneousHeaderValues) | ||||
|                 } else { | ||||
|                     Ok(Command::Brightness(payload[0])) | ||||
|                 } | ||||
|             } | ||||
|             CommandCode::HardReset => match check_command_only(value) { | ||||
|  | @ -238,6 +245,7 @@ impl TryFrom<Packet> for Command { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Helper method for BitMapLinear*-Commands into Packet
 | ||||
| fn bitmap_linear_into_packet( | ||||
|     command: CommandCode, | ||||
|     offset: Offset, | ||||
|  | @ -257,30 +265,12 @@ fn bitmap_linear_into_packet( | |||
|     ) | ||||
| } | ||||
| 
 | ||||
| fn origin_size_payload( | ||||
|     command: CommandCode, | ||||
|     origin: Origin, | ||||
|     size: Size, | ||||
|     payload: Vec<u8>, | ||||
| ) -> Packet { | ||||
|     let Origin(x, y) = origin; | ||||
|     let Size(w, h) = size; | ||||
|     Packet(Header(command.into(), x, y, w, h), payload.into()) | ||||
| } | ||||
| 
 | ||||
| /// 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![]) | ||||
| } | ||||
| 
 | ||||
| fn check_empty_header(header: Header) -> Option<TryFromPacketError> { | ||||
|     let Header(_, a, b, c, d) = header; | ||||
|     if a != 0 || b != 0 || c != 0 || d != 0 { | ||||
|         Some(TryFromPacketError::ExtraneousHeaderValues) | ||||
|     } else { | ||||
|         None | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Helper method for checking that a packet is empty and only contains a command code
 | ||||
| fn check_command_only(packet: Packet) -> Option<TryFromPacketError> { | ||||
|     let Packet(Header(_, a, b, c, d), payload) = packet; | ||||
|     if payload.len() != 0 { | ||||
|  | @ -292,6 +282,7 @@ fn check_command_only(packet: Packet) -> Option<TryFromPacketError> { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Helper method for Packets into BitMapLinear*-Commands
 | ||||
| fn packet_into_linear_bitmap( | ||||
|     packet: Packet, | ||||
| ) -> Result<(BitVec, CompressionCode), TryFromPacketError> { | ||||
|  | @ -323,21 +314,17 @@ pub mod c_api | |||
| 
 | ||||
|     use crate::{BitVec, Brightness, ByteGrid, Command, CompressionCode, Offset, Origin, Packet, PixelGrid}; | ||||
| 
 | ||||
|     /// Tries to load a `Command` from the passed array with the specified length.
 | ||||
| 
 | ||||
|     /// Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.
 | ||||
|     ///
 | ||||
|     /// returns: NULL in case of an error, pointer to the allocated command otherwise
 | ||||
|     /// Returns: pointer to command or NULL
 | ||||
|     #[no_mangle] | ||||
|     pub unsafe extern "C" fn sp2_command_try_load(data: *const u8, length: usize) -> *mut Command { | ||||
|         let data = std::slice::from_raw_parts(data, length); | ||||
|         let packet = match Packet::try_from(data) { | ||||
|     pub unsafe extern "C" fn sp2_command_try_from_packet(packet: *mut Packet) -> *mut Command { | ||||
|         let packet = *Box::from_raw(packet); | ||||
|         match Command::try_from(packet) { | ||||
|             Err(_) => return null_mut(), | ||||
|             Ok(packet) => packet | ||||
|         }; | ||||
|         let command = match Command::try_from(packet) { | ||||
|             Err(_) => return null_mut(), | ||||
|             Ok(command) => command, | ||||
|         }; | ||||
|         Box::into_raw(Box::new(command)) | ||||
|             Ok(command) => Box::into_raw(Box::new(command)), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Clones a `Command` instance
 | ||||
|  |  | |||
|  | @ -1,9 +1,7 @@ | |||
| use CommandCode::*; | ||||
| 
 | ||||
| /// The codes used for the commands. See the documentation on the corresponding commands.
 | ||||
| /// The u16 command codes used for the `Commands`.
 | ||||
| #[repr(u16)] | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| pub enum CommandCode { | ||||
| pub(crate) enum CommandCode { | ||||
|     Clear = 0x0002, | ||||
|     Cp437Data = 0x0003, | ||||
|     CharBrightness = 0x0005, | ||||
|  | @ -19,16 +17,20 @@ pub enum CommandCode { | |||
|     BitmapLinearXor = 0x0016, | ||||
| } | ||||
| 
 | ||||
| impl Into<u16> for CommandCode { | ||||
|     fn into(self) -> u16 { | ||||
|         self as u16 | ||||
| impl From<CommandCode> for u16 { | ||||
|     /// returns the u16 command code corresponding to the enum value
 | ||||
|     fn from(value: CommandCode) -> Self { | ||||
|         value as u16 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TryFrom<u16> for CommandCode { | ||||
|     type Error = (); | ||||
| 
 | ||||
|     /// Returns the enum value for the specified `u16` or `Error` if the code is unknown.
 | ||||
|     fn try_from(value: u16) -> Result<Self, Self::Error> { | ||||
|         use CommandCode::*; | ||||
| 
 | ||||
|         match value { | ||||
|             value if value == Clear as u16 => Ok(Clear), | ||||
|             value if value == Cp437Data as u16 => Ok(Cp437Data), | ||||
|  |  | |||
|  | @ -15,9 +15,9 @@ pub enum CompressionCode { | |||
|     Zs = 0x7a73, | ||||
| } | ||||
| 
 | ||||
| impl Into<u16> for CompressionCode { | ||||
|     fn into(self) -> u16 { | ||||
|         self as u16 | ||||
| impl From<CompressionCode> for u16 { | ||||
|     fn from(value: CompressionCode) -> Self { | ||||
|         value as u16 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,7 +42,7 @@ impl Connection { | |||
|     ///     .expect("connection failed");
 | ||||
|     ///
 | ||||
|     ///  // turn off all pixels
 | ||||
|     ///  connection.send(servicepoint2::Command::Clear)
 | ||||
|     ///  connection.send(servicepoint2::Command::Clear.into())
 | ||||
|     ///     .expect("send failed");
 | ||||
|     ///
 | ||||
|     ///  // turn on all pixels
 | ||||
|  | @ -50,12 +50,12 @@ impl Connection { | |||
|     ///  pixels.fill(true);
 | ||||
|     ///
 | ||||
|     ///  // send pixels to display
 | ||||
|     ///  connection.send(servicepoint2::Command::BitmapLinearWin(servicepoint2::Origin::top_left(), pixels))
 | ||||
|     ///  connection.send(servicepoint2::Command::BitmapLinearWin(servicepoint2::Origin::top_left(), pixels).into())
 | ||||
|     ///     .expect("send failed");
 | ||||
|     /// ```
 | ||||
|     pub fn send( | ||||
|         &self, | ||||
|         packet: impl Into<Packet> + Debug, | ||||
|         packet: Packet, | ||||
|     ) -> Result<(), std::io::Error> { | ||||
|         debug!("sending {packet:?}"); | ||||
|         let packet: Packet = packet.into(); | ||||
|  | @ -71,7 +71,7 @@ pub mod c_api | |||
|     use std::ffi::{c_char, CStr}; | ||||
|     use std::ptr::null_mut; | ||||
| 
 | ||||
|     use crate::{Command, Connection}; | ||||
|     use crate::{Connection, Packet}; | ||||
| 
 | ||||
|     /// Creates a new instance of Connection.
 | ||||
|     /// The returned instance has to be deallocated with `connection_dealloc`.
 | ||||
|  | @ -87,15 +87,14 @@ pub mod c_api | |||
|             Ok(value) => value | ||||
|         }; | ||||
| 
 | ||||
|         let boxed = Box::new(connection); | ||||
|         Box::into_raw(boxed) | ||||
|         Box::into_raw(Box::new(connection)) | ||||
|     } | ||||
| 
 | ||||
|     /// Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.
 | ||||
|     #[no_mangle] | ||||
|     pub unsafe extern "C" fn sp2_connection_send(connection: *const Connection, command_ptr: *mut Command) -> bool{ | ||||
|         let command = Box::from_raw(command_ptr); | ||||
|         (*connection).send(*command).is_ok() | ||||
|     pub unsafe extern "C" fn sp2_connection_send(connection: *const Connection, command_ptr: *mut Packet) -> bool{ | ||||
|         let packet = Box::from_raw(command_ptr); | ||||
|         (*connection).send(*packet).is_ok() | ||||
|     } | ||||
| 
 | ||||
|     /// Closes and deallocates a connection instance
 | ||||
|  |  | |||
|  | @ -1,12 +1,14 @@ | |||
| pub use crate::bit_vec::BitVec; | ||||
| pub use crate::byte_grid::ByteGrid; | ||||
| pub use crate::command::{Brightness, Command, Offset, Origin, Size}; | ||||
| pub use crate::command_code::CommandCode; | ||||
| pub use crate::compression_code::CompressionCode; | ||||
| pub use crate::connection::Connection; | ||||
| pub use crate::packet::{Header, Packet, Payload}; | ||||
| pub use crate::pixel_grid::PixelGrid; | ||||
| 
 | ||||
| #[cfg(feature = "c-api")] | ||||
| pub use crate::c_slice::CByteSlice; | ||||
| 
 | ||||
| mod bit_vec; | ||||
| mod byte_grid; | ||||
| mod command; | ||||
|  | @ -16,6 +18,7 @@ mod compression_code; | |||
| mod connection; | ||||
| mod packet; | ||||
| mod pixel_grid; | ||||
| mod c_slice; | ||||
| 
 | ||||
| /// size of a single tile in one dimension
 | ||||
| pub const TILE_SIZE: u16 = 8; | ||||
|  |  | |||
|  | @ -1,3 +1,5 @@ | |||
| use std::mem::size_of; | ||||
| 
 | ||||
| /// A raw header. Should probably not be used directly.
 | ||||
| #[derive(Debug)] | ||||
| pub struct Header(pub u16, pub u16, pub u16, pub u16, pub u16); | ||||
|  | @ -9,12 +11,13 @@ pub type Payload = Vec<u8>; | |||
| #[derive(Debug)] | ||||
| pub struct Packet(pub Header, pub Payload); | ||||
| 
 | ||||
| impl Into<Payload> for Packet { | ||||
|     fn into(self) -> Vec<u8> { | ||||
|         let Packet(Header(mode, a, b, c, d), payload) = self; | ||||
| impl From<Packet> for Vec<u8> { | ||||
|     /// Turn the packet into raw bytes ready to send
 | ||||
|     fn from(value: Packet) -> Self { | ||||
|         let Packet(Header(mode, a, b, c, d), payload) = value; | ||||
| 
 | ||||
|         let mut packet = vec![0u8; 10 + payload.len()]; | ||||
|         packet[0..=1].copy_from_slice(&u16::to_be_bytes(mode)); | ||||
|         packet[0..=1].copy_from_slice(&u16::to_be_bytes(mode.into())); | ||||
|         packet[2..=3].copy_from_slice(&u16::to_be_bytes(a)); | ||||
|         packet[4..=5].copy_from_slice(&u16::to_be_bytes(b)); | ||||
|         packet[6..=7].copy_from_slice(&u16::to_be_bytes(c)); | ||||
|  | @ -33,8 +36,17 @@ fn u16_from_be_slice(slice: &[u8]) -> u16 { | |||
|     u16::from_be_bytes(bytes) | ||||
| } | ||||
| 
 | ||||
| impl From<Payload> for Packet { | ||||
|     fn from(value: Vec<u8>) -> Self { | ||||
| impl TryFrom<&[u8]> for Packet { | ||||
|     type Error = (); | ||||
| 
 | ||||
|     /// Tries to interpret the bytes as a `Packet`.
 | ||||
|     ///
 | ||||
|     /// returns: `Error` if slice is not long enough to be a `Packet`
 | ||||
|     fn try_from(value: &[u8]) -> Result<Self, Self::Error> { | ||||
|         if value.len() < size_of::<Header>() { | ||||
|             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]); | ||||
|  | @ -42,19 +54,42 @@ impl From<Payload> for Packet { | |||
|         let d = u16_from_be_slice(&value[8..=9]); | ||||
|         let payload = value[10..].to_vec(); | ||||
| 
 | ||||
|         Packet(Header(mode, a, b, c, d), payload) | ||||
|         Ok(Packet(Header(mode, a, b, c, d), payload)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<&[u8]> for Packet { | ||||
|     fn from(value: &[u8]) -> Self { | ||||
|         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 payload = value[10..].to_vec(); | ||||
| #[cfg(feature = "c-api")] | ||||
| mod c_api { | ||||
|     use std::ptr::null_mut; | ||||
| 
 | ||||
|         Packet(Header(mode, a, b, c, d), payload) | ||||
|     use crate::{Command, Packet}; | ||||
| 
 | ||||
|     /// Turns a `Command` into a `Packet`. The command gets deallocated in the process.
 | ||||
|     #[no_mangle] | ||||
|     pub unsafe extern "C" fn sp2_packet_from_command(command: *mut Command) -> *mut Packet { | ||||
|         let command = *Box::from_raw(command); | ||||
|         let packet = command.into(); | ||||
|         Box::into_raw(Box::new(packet)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|     /// Tries to load a `Packet` from the passed array with the specified length.
 | ||||
|     ///
 | ||||
|     /// returns: NULL in case of an error, pointer to the allocated packet otherwise
 | ||||
|     #[no_mangle] | ||||
|     pub unsafe extern "C" fn sp2_packet_try_load(data: *const u8, length: usize) -> *mut Packet { | ||||
|         let data = std::slice::from_raw_parts(data, length); | ||||
|         match Packet::try_from(data) { | ||||
|             Err(_) => null_mut(), | ||||
|             Ok(packet) => Box::into_raw(Box::new(packet)) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Deallocates a `Packet`.
 | ||||
|     ///
 | ||||
|     /// Note: do not call this if the instance has been consumed in another way, e.g. by sending it.
 | ||||
|     #[no_mangle] | ||||
|     pub unsafe extern "C" fn sp2_packet_dealloc(this: *mut Packet) { | ||||
|         _ = Box::from_raw(this) | ||||
|     } | ||||
| } | ||||
|  | @ -77,20 +77,22 @@ impl PixelGrid { | |||
|         self.bit_vec.fill(value); | ||||
|     } | ||||
| 
 | ||||
|     pub fn data_ref(&self) -> &[u8] { | ||||
|         self.bit_vec.data_ref() | ||||
|     pub fn mut_data_ref(&mut self) -> &mut [u8] { | ||||
|         self.bit_vec.mut_data_ref() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Into<Vec<u8>> for PixelGrid { | ||||
|     fn into(self) -> Vec<u8> { | ||||
|         self.bit_vec.into() | ||||
| impl From<PixelGrid> for Vec<u8> { | ||||
|     /// Turns a `PixelGrid` into the underlying `Vec<u8>`.
 | ||||
|     fn from(value: PixelGrid) -> Self { | ||||
|         value.bit_vec.into() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(feature = "c-api")] | ||||
| pub mod c_api | ||||
| { | ||||
|     use crate::c_slice::CByteSlice; | ||||
|     use crate::PixelGrid; | ||||
| 
 | ||||
|     /// Creates a new `PixelGrid` instance.
 | ||||
|  | @ -153,10 +155,21 @@ pub mod c_api | |||
|         (*this).height | ||||
|     } | ||||
| 
 | ||||
|     /// Gets a reference to the data of the `PixelGrid` instance.
 | ||||
|     /// Gets an unsafe reference to the data of the `PixelGrid` instance.
 | ||||
|     ///
 | ||||
|     /// ## Safety
 | ||||
|     ///
 | ||||
|     /// The caller has to make sure to never access the returned memory after the `PixelGrid`
 | ||||
|     /// instance has been consumed or manually deallocated.
 | ||||
|     ///
 | ||||
|     /// Reading and writing concurrently to either the original instance or the returned data will
 | ||||
|     /// result in undefined behavior.
 | ||||
|     #[no_mangle] | ||||
|     pub unsafe extern "C" fn sp2_pixel_grid_data_ref(this: *const PixelGrid) -> *const u8 { | ||||
|         // TODO: also return length
 | ||||
|         (*this).data_ref().as_ptr_range().start | ||||
|     pub unsafe extern "C" fn sp2_pixel_grid_unsafe_data_ref(this: *mut PixelGrid) -> CByteSlice { | ||||
|         let data = (*this).mut_data_ref(); | ||||
|         CByteSlice { | ||||
|             start: data.as_mut_ptr_range().start, | ||||
|             length: data.len(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vinzenz Schroeter
						Vinzenz Schroeter