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