Merge branch 'uniffi-prerequisites' into 'main'
see https://github.com/cccb/servicepoint/pull/19/
This commit is contained in:
		
						commit
						11ec30ca74
					
				
					 25 changed files with 496 additions and 276 deletions
				
			
		
							
								
								
									
										103
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										103
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							|  | @ -19,9 +19,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "anstream" | name = "anstream" | ||||||
| version = "0.6.15" | version = "0.6.18" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "anstyle", |  "anstyle", | ||||||
|  "anstyle-parse", |  "anstyle-parse", | ||||||
|  | @ -34,36 +34,36 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "anstyle" | name = "anstyle" | ||||||
| version = "1.0.8" | version = "1.0.10" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "anstyle-parse" | name = "anstyle-parse" | ||||||
| version = "0.2.5" | version = "0.2.6" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "utf8parse", |  "utf8parse", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "anstyle-query" | name = "anstyle-query" | ||||||
| version = "1.1.1" | version = "1.1.2" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "windows-sys 0.52.0", |  "windows-sys 0.59.0", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "anstyle-wincon" | name = "anstyle-wincon" | ||||||
| version = "3.0.4" | version = "3.0.6" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" | checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "anstyle", |  "anstyle", | ||||||
|  "windows-sys 0.52.0", |  "windows-sys 0.59.0", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
|  | @ -101,9 +101,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "bytes" | name = "bytes" | ||||||
| version = "1.7.2" | version = "1.8.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" | checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "bzip2" | name = "bzip2" | ||||||
|  | @ -147,9 +147,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "cc" | name = "cc" | ||||||
| version = "1.1.30" | version = "1.2.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" | checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "jobserver", |  "jobserver", | ||||||
|  "libc", |  "libc", | ||||||
|  | @ -204,15 +204,15 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "colorchoice" | name = "colorchoice" | ||||||
| version = "1.0.2" | version = "1.0.3" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "cpufeatures" | name = "cpufeatures" | ||||||
| version = "0.2.14" | version = "0.2.15" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" | checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "libc", |  "libc", | ||||||
| ] | ] | ||||||
|  | @ -280,9 +280,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "fastrand" | name = "fastrand" | ||||||
| version = "2.1.1" | version = "2.2.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" | checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "flate2" | name = "flate2" | ||||||
|  | @ -329,9 +329,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "hashbrown" | name = "hashbrown" | ||||||
| version = "0.15.0" | version = "0.15.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" | checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "heck" | name = "heck" | ||||||
|  | @ -403,9 +403,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "libc" | name = "libc" | ||||||
| version = "0.2.159" | version = "0.2.162" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" | checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "linux-raw-sys" | name = "linux-raw-sys" | ||||||
|  | @ -457,9 +457,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "proc-macro2" | name = "proc-macro2" | ||||||
| version = "1.0.87" | version = "1.0.89" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" | checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "unicode-ident", |  "unicode-ident", | ||||||
| ] | ] | ||||||
|  | @ -511,9 +511,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "regex" | name = "regex" | ||||||
| version = "1.11.0" | version = "1.11.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "aho-corasick", |  "aho-corasick", | ||||||
|  "memchr", |  "memchr", | ||||||
|  | @ -523,9 +523,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "regex-automata" | name = "regex-automata" | ||||||
| version = "0.4.8" | version = "0.4.9" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "aho-corasick", |  "aho-corasick", | ||||||
|  "memchr", |  "memchr", | ||||||
|  | @ -550,9 +550,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "rustix" | name = "rustix" | ||||||
| version = "0.38.37" | version = "0.38.40" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" | checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "bitflags", |  "bitflags", | ||||||
|  "errno", |  "errno", | ||||||
|  | @ -569,18 +569,18 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "serde" | name = "serde" | ||||||
| version = "1.0.210" | version = "1.0.215" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" | checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "serde_derive", |  "serde_derive", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "serde_derive" | name = "serde_derive" | ||||||
| version = "1.0.210" | version = "1.0.215" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" | checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  | @ -589,9 +589,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "serde_json" | name = "serde_json" | ||||||
| version = "1.0.128" | version = "1.0.132" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" | checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "itoa", |  "itoa", | ||||||
|  "memchr", |  "memchr", | ||||||
|  | @ -610,7 +610,7 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "servicepoint" | name = "servicepoint" | ||||||
| version = "0.10.0" | version = "0.11.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "bitvec", |  "bitvec", | ||||||
|  "bzip2", |  "bzip2", | ||||||
|  | @ -620,13 +620,14 @@ dependencies = [ | ||||||
|  "once_cell", |  "once_cell", | ||||||
|  "rand", |  "rand", | ||||||
|  "rust-lzma", |  "rust-lzma", | ||||||
|  |  "thiserror", | ||||||
|  "tungstenite", |  "tungstenite", | ||||||
|  "zstd", |  "zstd", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "servicepoint_binding_c" | name = "servicepoint_binding_c" | ||||||
| version = "0.10.0" | version = "0.11.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "cbindgen", |  "cbindgen", | ||||||
|  "servicepoint", |  "servicepoint", | ||||||
|  | @ -634,7 +635,7 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "servicepoint_binding_cs" | name = "servicepoint_binding_cs" | ||||||
| version = "0.10.0" | version = "0.11.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "csbindgen", |  "csbindgen", | ||||||
|  "servicepoint", |  "servicepoint", | ||||||
|  | @ -666,9 +667,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "syn" | name = "syn" | ||||||
| version = "2.0.79" | version = "2.0.87" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" | checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  | @ -683,9 +684,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "tempfile" | name = "tempfile" | ||||||
| version = "3.13.0" | version = "3.14.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" | checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "cfg-if", |  "cfg-if", | ||||||
|  "fastrand", |  "fastrand", | ||||||
|  | @ -696,18 +697,18 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "thiserror" | name = "thiserror" | ||||||
| version = "1.0.64" | version = "1.0.69" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "thiserror-impl", |  "thiserror-impl", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "thiserror-impl" | name = "thiserror-impl" | ||||||
| version = "1.0.64" | version = "1.0.69" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  |  | ||||||
|  | @ -8,7 +8,10 @@ members = [ | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [workspace.package] | [workspace.package] | ||||||
| version = "0.10.0" | version = "0.11.0" | ||||||
| 
 | 
 | ||||||
| [workspace.lints.rust] | [workspace.lints.rust] | ||||||
| missing-docs = "warn" | missing-docs = "warn" | ||||||
|  | 
 | ||||||
|  | [workspace.dependencies] | ||||||
|  | thiserror = "1.0.69" | ||||||
|  | @ -22,6 +22,7 @@ rust-lzma = { version = "0.6.0", optional = true } | ||||||
| rand = { version = "0.8", optional = true } | rand = { version = "0.8", optional = true } | ||||||
| tungstenite = { version = "0.24.0", optional = true } | tungstenite = { version = "0.24.0", optional = true } | ||||||
| once_cell = { version = "1.20.2", optional = true } | once_cell = { version = "1.20.2", optional = true } | ||||||
|  | thiserror.workspace = true | ||||||
| 
 | 
 | ||||||
| [features] | [features] | ||||||
| default = ["compression_lzma", "protocol_udp", "cp437"] | default = ["compression_lzma", "protocol_udp", "cp437"] | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ cargo add servicepoint | ||||||
| or | or | ||||||
| ```toml | ```toml | ||||||
| [dependencies] | [dependencies] | ||||||
| servicepoint = "0.10.0" | servicepoint = "0.11.0" | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Examples | ## Examples | ||||||
|  |  | ||||||
|  | @ -42,10 +42,10 @@ fn main() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let text = cli.text.join("\n"); |     let text = cli.text.join("\n"); | ||||||
|     let grid = CharGrid::from(&*text); |     let grid = CharGrid::from(text); | ||||||
|     let cp437_grid = Cp437Grid::from(&grid); |     let grid = Cp437Grid::from(grid); | ||||||
| 
 | 
 | ||||||
|     connection |     connection | ||||||
|         .send(Command::Cp437Data(Origin::ZERO, cp437_grid)) |         .send(Command::Cp437Data(Origin::ZERO, grid)) | ||||||
|         .expect("sending text failed"); |         .expect("sending text failed"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5,20 +5,17 @@ use servicepoint::{ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| fn main() { | fn main() { | ||||||
|     // make connection mut
 |     let connection = | ||||||
|     let mut connection = |  | ||||||
|         Connection::open_websocket("ws://localhost:8080".parse().unwrap()) |         Connection::open_websocket("ws://localhost:8080".parse().unwrap()) | ||||||
|             .unwrap(); |             .unwrap(); | ||||||
| 
 | 
 | ||||||
|     // use send_mut instead of send
 |     connection.send(Command::Clear).unwrap(); | ||||||
|     connection.send_mut(Command::Clear).unwrap(); |  | ||||||
| 
 | 
 | ||||||
|     let mut pixels = Bitmap::max_sized(); |     let mut pixels = Bitmap::max_sized(); | ||||||
|     pixels.fill(true); |     pixels.fill(true); | ||||||
| 
 | 
 | ||||||
|     // use send_mut instead of send
 |  | ||||||
|     connection |     connection | ||||||
|         .send_mut(Command::BitmapLinearWin( |         .send(Command::BitmapLinearWin( | ||||||
|             Origin::ZERO, |             Origin::ZERO, | ||||||
|             pixels, |             pixels, | ||||||
|             CompressionCode::Lzma, |             CompressionCode::Lzma, | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ use std::time::Duration; | ||||||
| 
 | 
 | ||||||
| use clap::Parser; | use clap::Parser; | ||||||
| 
 | 
 | ||||||
| use servicepoint::{bitvec::prelude::BitVec, *}; | use servicepoint::*; | ||||||
| 
 | 
 | ||||||
| #[derive(Parser, Debug)] | #[derive(Parser, Debug)] | ||||||
| struct Cli { | struct Cli { | ||||||
|  | @ -33,12 +33,8 @@ fn main() { | ||||||
|             enabled_pixels.set(x_offset % PIXEL_WIDTH, y, false); |             enabled_pixels.set(x_offset % PIXEL_WIDTH, y, false); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // this works because the pixel grid has max size
 |  | ||||||
|         let pixel_data: Vec<u8> = enabled_pixels.clone().into(); |  | ||||||
|         let bit_vec = BitVec::from_vec(pixel_data); |  | ||||||
| 
 |  | ||||||
|         connection |         connection | ||||||
|             .send(Command::BitmapLinearAnd(0, bit_vec, CompressionCode::Lzma)) |             .send(Command::BitmapLinearWin(Origin::ZERO, enabled_pixels.clone(), CompressionCode::Lzma)) | ||||||
|             .expect("could not send command to display"); |             .expect("could not send command to display"); | ||||||
|         thread::sleep(sleep_duration); |         thread::sleep(sleep_duration); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -2,14 +2,14 @@ use bitvec::order::Msb0; | ||||||
| use bitvec::prelude::BitSlice; | use bitvec::prelude::BitSlice; | ||||||
| use bitvec::slice::IterMut; | use bitvec::slice::IterMut; | ||||||
| 
 | 
 | ||||||
| use crate::{BitVec, DataRef, Grid, SpBitVec, PIXEL_HEIGHT, PIXEL_WIDTH}; | use crate::{BitVec, DataRef, Grid, PIXEL_HEIGHT, PIXEL_WIDTH}; | ||||||
| 
 | 
 | ||||||
| /// A grid of pixels stored in packed bytes.
 | /// A grid of pixels stored in packed bytes.
 | ||||||
| #[derive(Debug, Clone, PartialEq)] | #[derive(Debug, Clone, PartialEq, Eq)] | ||||||
| pub struct Bitmap { | pub struct Bitmap { | ||||||
|     width: usize, |     width: usize, | ||||||
|     height: usize, |     height: usize, | ||||||
|     bit_vec: SpBitVec, |     bit_vec: BitVec, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Bitmap { | impl Bitmap { | ||||||
|  | @ -175,6 +175,12 @@ impl From<Bitmap> for Vec<u8> { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl From<Bitmap> for BitVec { | ||||||
|  |     fn from(value: Bitmap) -> Self { | ||||||
|  |         value.bit_vec | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub struct IterRows<'t> { | pub struct IterRows<'t> { | ||||||
|     bitmap: &'t Bitmap, |     bitmap: &'t Bitmap, | ||||||
|     row: usize, |     row: usize, | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ use rand::{ | ||||||
| /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | /// # let connection = Connection::open("127.0.0.1:2342").unwrap();
 | ||||||
| /// let result = connection.send(Command::Brightness(b));
 | /// let result = connection.send(Command::Brightness(b));
 | ||||||
| /// ```
 | /// ```
 | ||||||
| #[derive(Debug, Copy, Clone, PartialEq)] | #[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)] | ||||||
| pub struct Brightness(u8); | pub struct Brightness(u8); | ||||||
| 
 | 
 | ||||||
| /// A grid containing brightness values.
 | /// A grid containing brightness values.
 | ||||||
|  | @ -37,8 +37,21 @@ pub struct Brightness(u8); | ||||||
| /// ```
 | /// ```
 | ||||||
| pub type BrightnessGrid = PrimitiveGrid<Brightness>; | pub type BrightnessGrid = PrimitiveGrid<Brightness>; | ||||||
| 
 | 
 | ||||||
|  | impl BrightnessGrid { | ||||||
|  |     /// Like [Self::load], but ignoring any out-of-range brightness values
 | ||||||
|  |     pub fn saturating_load(width: usize, height: usize, data: &[u8]) -> Self { | ||||||
|  |         PrimitiveGrid::load(width, height, data).map(Brightness::saturating_from) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl From<Brightness> for u8 { | impl From<Brightness> for u8 { | ||||||
|     fn from(brightness: Brightness) -> Self { |     fn from(brightness: Brightness) -> Self { | ||||||
|  |         Self::from(&brightness) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<&Brightness> for u8 { | ||||||
|  |     fn from(brightness: &Brightness) -> Self { | ||||||
|         brightness.0 |         brightness.0 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -105,7 +118,7 @@ impl TryFrom<PrimitiveGrid<u8>> for BrightnessGrid { | ||||||
|         let brightnesses = value |         let brightnesses = value | ||||||
|             .iter() |             .iter() | ||||||
|             .map(|b| Brightness::try_from(*b)) |             .map(|b| Brightness::try_from(*b)) | ||||||
|             .collect::<Result<Vec<Brightness>, _>>()?; |             .collect::<Result<Vec<_>, _>>()?; | ||||||
|         Ok(BrightnessGrid::load( |         Ok(BrightnessGrid::load( | ||||||
|             value.width(), |             value.width(), | ||||||
|             value.height(), |             value.height(), | ||||||
|  | @ -129,7 +142,7 @@ mod tests { | ||||||
|     #[test] |     #[test] | ||||||
|     fn brightness_from_u8() { |     fn brightness_from_u8() { | ||||||
|         assert_eq!(Err(100), Brightness::try_from(100)); |         assert_eq!(Err(100), Brightness::try_from(100)); | ||||||
|         assert_eq!(Ok(Brightness(1)), Brightness::try_from(1)) |         assert_eq!(Ok(Brightness(1)), Brightness::try_from(1)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|  | @ -155,4 +168,10 @@ mod tests { | ||||||
|         assert_eq!(Brightness::MAX, Brightness::saturating_from(100)); |         assert_eq!(Brightness::MAX, Brightness::saturating_from(100)); | ||||||
|         assert_eq!(Brightness(5), Brightness::saturating_from(5)); |         assert_eq!(Brightness(5), Brightness::saturating_from(5)); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn saturating_load() { | ||||||
|  |         assert_eq!(BrightnessGrid::load(2,2, &[Brightness::MAX, Brightness::MAX, Brightness::MIN, Brightness::MAX]), | ||||||
|  |             BrightnessGrid::saturating_load(2,2, &[255u8, 23, 0, 42])); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										129
									
								
								crates/servicepoint/src/char_grid.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								crates/servicepoint/src/char_grid.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,129 @@ | ||||||
|  | use crate::primitive_grid::SeriesError; | ||||||
|  | use crate::{Grid, PrimitiveGrid}; | ||||||
|  | 
 | ||||||
|  | /// A grid containing UTF-8 characters.
 | ||||||
|  | pub type CharGrid = PrimitiveGrid<char>; | ||||||
|  | 
 | ||||||
|  | impl CharGrid { | ||||||
|  |     /// Copies a column from the grid as a String.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Returns [None] if x is out of bounds.
 | ||||||
|  |     pub fn get_col_str(&self, x: usize) -> Option<String> { | ||||||
|  |         Some(String::from_iter(self.get_col(x)?)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Copies a row from the grid as a String.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Returns [None] if y is out of bounds.
 | ||||||
|  |     pub fn get_row_str(&self, y: usize) -> Option<String> { | ||||||
|  |         Some(String::from_iter(self.get_row(y)?)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Overwrites a row in the grid with a str.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Returns [SeriesError] if y is out of bounds or `row` is not of the correct size.
 | ||||||
|  |     pub fn set_row_str( | ||||||
|  |         &mut self, | ||||||
|  |         y: usize, | ||||||
|  |         value: &str, | ||||||
|  |     ) -> Result<(), SeriesError> { | ||||||
|  |         self.set_row(y, value.chars().collect::<Vec<_>>().as_ref()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Overwrites a column in the grid with a str.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Returns [SeriesError] if y is out of bounds or `row` is not of the correct size.
 | ||||||
|  |     pub fn set_col_str( | ||||||
|  |         &mut self, | ||||||
|  |         x: usize, | ||||||
|  |         value: &str, | ||||||
|  |     ) -> Result<(), SeriesError> { | ||||||
|  |         self.set_col(x, value.chars().collect::<Vec<_>>().as_ref()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<&str> for CharGrid { | ||||||
|  |     fn from(value: &str) -> Self { | ||||||
|  |         let value = value.replace("\r\n", "\n"); | ||||||
|  |         let mut lines = value | ||||||
|  |             .split('\n') | ||||||
|  |             .map(move |line| line.trim_end()) | ||||||
|  |             .collect::<Vec<_>>(); | ||||||
|  |         let width = | ||||||
|  |             lines.iter().fold(0, move |a, x| std::cmp::max(a, x.len())); | ||||||
|  | 
 | ||||||
|  |         while lines.last().is_some_and(move |line| line.is_empty()) { | ||||||
|  |             _ = lines.pop(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let mut grid = Self::new(width, lines.len()); | ||||||
|  |         for (y, line) in lines.iter().enumerate() { | ||||||
|  |             for (x, char) in line.chars().enumerate() { | ||||||
|  |                 grid.set(x, y, char); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         grid | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<String> for CharGrid { | ||||||
|  |     fn from(value: String) -> Self { | ||||||
|  |         CharGrid::from(&*value) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<&CharGrid> for String { | ||||||
|  |     fn from(value: &CharGrid) -> Self { | ||||||
|  |         value | ||||||
|  |             .iter_rows() | ||||||
|  |             .map(move |chars| { | ||||||
|  |                 chars | ||||||
|  |                     .collect::<String>() | ||||||
|  |                     .replace('\0', " ") | ||||||
|  |                     .trim_end() | ||||||
|  |                     .to_string() | ||||||
|  |             }) | ||||||
|  |             .collect::<Vec<_>>() | ||||||
|  |             .join("\n") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[cfg(test)] | ||||||
|  | mod test { | ||||||
|  |     use super::*; | ||||||
|  |     use crate::Grid; | ||||||
|  |     #[test] | ||||||
|  |     fn col_str() { | ||||||
|  |         let mut grid = CharGrid::new(2, 3); | ||||||
|  |         assert_eq!(grid.get_col_str(2), None); | ||||||
|  |         assert_eq!(grid.get_col_str(1), Some(String::from("\0\0\0"))); | ||||||
|  |         assert_eq!(grid.set_col_str(1, "abc"), Ok(())); | ||||||
|  |         assert_eq!(grid.get_col_str(1), Some(String::from("abc"))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn row_str() { | ||||||
|  |         let mut grid = CharGrid::new(2, 3); | ||||||
|  |         assert_eq!(grid.get_row_str(3), None); | ||||||
|  |         assert_eq!(grid.get_row_str(1), Some(String::from("\0\0"))); | ||||||
|  |         assert_eq!( | ||||||
|  |             grid.set_row_str(1, "abc"), | ||||||
|  |             Err(SeriesError::InvalidLength { | ||||||
|  |                 expected: 2, | ||||||
|  |                 actual: 3 | ||||||
|  |             }) | ||||||
|  |         ); | ||||||
|  |         assert_eq!(grid.set_row_str(1, "ab"), Ok(())); | ||||||
|  |         assert_eq!(grid.get_row_str(1), Some(String::from("ab"))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn str_to_char_grid() { | ||||||
|  |         let original = "Hello\r\nWorld!\n...\n"; | ||||||
|  |         let grid = CharGrid::from(original); | ||||||
|  |         assert_eq!(3, grid.height()); | ||||||
|  |         let actual = String::from(&grid); | ||||||
|  |         assert_eq!("Hello\nWorld!\n...", actual); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,11 +1,9 @@ | ||||||
| use bitvec::prelude::BitVec; |  | ||||||
| 
 |  | ||||||
| use crate::{ | use crate::{ | ||||||
|     command_code::CommandCode, |     command_code::CommandCode, | ||||||
|     compression::into_decompressed, |     compression::into_decompressed, | ||||||
|     packet::{Header, Packet}, |     packet::{Header, Packet}, | ||||||
|     Bitmap, Brightness, BrightnessGrid, CompressionCode, Cp437Grid, Origin, |     Bitmap, Brightness, BrightnessGrid, CompressionCode, Cp437Grid, Origin, | ||||||
|     Pixels, PrimitiveGrid, SpBitVec, Tiles, TILE_SIZE, |     Pixels, PrimitiveGrid, BitVec, Tiles, TILE_SIZE, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Type alias for documenting the meaning of the u16 in enum values
 | /// Type alias for documenting the meaning of the u16 in enum values
 | ||||||
|  | @ -144,7 +142,7 @@ pub enum Command { | ||||||
|     /// once the starting row is full, overwriting will continue on column 0.
 |     /// once the starting row is full, overwriting will continue on column 0.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// The contained [BitVec] is always uncompressed.
 |     /// The contained [BitVec] is always uncompressed.
 | ||||||
|     BitmapLinear(Offset, SpBitVec, CompressionCode), |     BitmapLinear(Offset, BitVec, CompressionCode), | ||||||
| 
 | 
 | ||||||
|     /// Set pixel data according to an and-mask starting at the offset.
 |     /// Set pixel data according to an and-mask starting at the offset.
 | ||||||
|     ///
 |     ///
 | ||||||
|  | @ -152,7 +150,7 @@ pub enum Command { | ||||||
|     /// once the starting row is full, overwriting will continue on column 0.
 |     /// once the starting row is full, overwriting will continue on column 0.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// The contained [BitVec] is always uncompressed.
 |     /// The contained [BitVec] is always uncompressed.
 | ||||||
|     BitmapLinearAnd(Offset, SpBitVec, CompressionCode), |     BitmapLinearAnd(Offset, BitVec, CompressionCode), | ||||||
| 
 | 
 | ||||||
|     /// Set pixel data according to an or-mask starting at the offset.
 |     /// Set pixel data according to an or-mask starting at the offset.
 | ||||||
|     ///
 |     ///
 | ||||||
|  | @ -160,7 +158,7 @@ pub enum Command { | ||||||
|     /// once the starting row is full, overwriting will continue on column 0.
 |     /// once the starting row is full, overwriting will continue on column 0.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// The contained [BitVec] is always uncompressed.
 |     /// The contained [BitVec] is always uncompressed.
 | ||||||
|     BitmapLinearOr(Offset, SpBitVec, CompressionCode), |     BitmapLinearOr(Offset, BitVec, CompressionCode), | ||||||
| 
 | 
 | ||||||
|     /// Set pixel data according to a xor-mask starting at the offset.
 |     /// Set pixel data according to a xor-mask starting at the offset.
 | ||||||
|     ///
 |     ///
 | ||||||
|  | @ -168,7 +166,7 @@ pub enum Command { | ||||||
|     /// once the starting row is full, overwriting will continue on column 0.
 |     /// once the starting row is full, overwriting will continue on column 0.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// The contained [BitVec] is always uncompressed.
 |     /// The contained [BitVec] is always uncompressed.
 | ||||||
|     BitmapLinearXor(Offset, SpBitVec, CompressionCode), |     BitmapLinearXor(Offset, BitVec, CompressionCode), | ||||||
| 
 | 
 | ||||||
|     /// Kills the udp daemon on the display, which usually results in a restart.
 |     /// Kills the udp daemon on the display, which usually results in a restart.
 | ||||||
|     ///
 |     ///
 | ||||||
|  | @ -214,21 +212,27 @@ pub enum Command { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Err values for [Command::try_from].
 | /// Err values for [Command::try_from].
 | ||||||
| #[derive(Debug, PartialEq)] | #[derive(Debug, PartialEq, thiserror::Error)] | ||||||
| pub enum TryFromPacketError { | pub enum TryFromPacketError { | ||||||
|     /// the contained command code does not correspond to a known command
 |     /// the contained command code does not correspond to a known command
 | ||||||
|  |     #[error("The command code {0:?} does not correspond to a known command")] | ||||||
|     InvalidCommand(u16), |     InvalidCommand(u16), | ||||||
|     /// the expected payload size was n, but size m was found
 |     /// the expected payload size was n, but size m was found
 | ||||||
|  |     #[error("the expected payload size was {0}, but size {1} was found")] | ||||||
|     UnexpectedPayloadSize(usize, usize), |     UnexpectedPayloadSize(usize, usize), | ||||||
|     /// Header fields not needed for the command have been used.
 |     /// Header fields not needed for the command have been used.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// Note that these commands would usually still work on the actual display.
 |     /// Note that these commands would usually still work on the actual display.
 | ||||||
|  |     #[error("Header fields not needed for the command have been used")] | ||||||
|     ExtraneousHeaderValues, |     ExtraneousHeaderValues, | ||||||
|     /// The contained compression code is not known. This could be of disabled features.
 |     /// The contained compression code is not known. This could be of disabled features.
 | ||||||
|  |     #[error("The compression code {0:?} does not correspond to a known compression algorithm.")] | ||||||
|     InvalidCompressionCode(u16), |     InvalidCompressionCode(u16), | ||||||
|     /// Decompression of the payload failed. This can be caused by corrupted packets.
 |     /// Decompression of the payload failed. This can be caused by corrupted packets.
 | ||||||
|  |     #[error("The decompression of the payload failed")] | ||||||
|     DecompressionFailed, |     DecompressionFailed, | ||||||
|     /// The given brightness value is out of bounds
 |     /// The given brightness value is out of bounds
 | ||||||
|  |     #[error("The given brightness value {0} is out of bounds.")] | ||||||
|     InvalidBrightness(u8), |     InvalidBrightness(u8), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -374,7 +378,7 @@ impl Command { | ||||||
|     /// Helper method for Packets into `BitmapLinear*`-Commands
 |     /// Helper method for Packets into `BitmapLinear*`-Commands
 | ||||||
|     fn packet_into_linear_bitmap( |     fn packet_into_linear_bitmap( | ||||||
|         packet: Packet, |         packet: Packet, | ||||||
|     ) -> Result<(SpBitVec, CompressionCode), TryFromPacketError> { |     ) -> Result<(BitVec, CompressionCode), TryFromPacketError> { | ||||||
|         let Packet { |         let Packet { | ||||||
|             header: |             header: | ||||||
|                 Header { |                 Header { | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| use std::fmt::Debug; |  | ||||||
| 
 |  | ||||||
| use crate::packet::Packet; | use crate::packet::Packet; | ||||||
|  | use std::fmt::Debug; | ||||||
| 
 | 
 | ||||||
| /// A connection to the display.
 | /// A connection to the display.
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -35,27 +34,24 @@ pub enum Connection { | ||||||
|     /// [servicepoint-websocket-relay]: https://github.com/kaesaecracker/servicepoint-websocket-relay
 |     /// [servicepoint-websocket-relay]: https://github.com/kaesaecracker/servicepoint-websocket-relay
 | ||||||
|     #[cfg(feature = "protocol_websocket")] |     #[cfg(feature = "protocol_websocket")] | ||||||
|     WebSocket( |     WebSocket( | ||||||
|         tungstenite::WebSocket< |         std::sync::Mutex< | ||||||
|             tungstenite::stream::MaybeTlsStream<std::net::TcpStream>, |             tungstenite::WebSocket< | ||||||
|  |                 tungstenite::stream::MaybeTlsStream<std::net::TcpStream>, | ||||||
|  |             >, | ||||||
|         >, |         >, | ||||||
|     ), |     ), | ||||||
| 
 | 
 | ||||||
|     /// A fake connection for testing that does not actually send anything.
 |     /// A fake connection for testing that does not actually send anything.
 | ||||||
|     ///
 |  | ||||||
|     /// This variant allows immutable send.
 |  | ||||||
|     Fake, |     Fake, | ||||||
| 
 |  | ||||||
|     /// A fake connection for testing that does not actually send anything.
 |  | ||||||
|     ///
 |  | ||||||
|     /// This variant does not allow immutable send.
 |  | ||||||
|     FakeMutableSend, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug, thiserror::Error)] | ||||||
| pub enum SendError { | pub enum SendError { | ||||||
|     IoError(std::io::Error), |     #[error("IO error occurred while sending")] | ||||||
|  |     IoError(#[from] std::io::Error), | ||||||
|     #[cfg(feature = "protocol_websocket")] |     #[cfg(feature = "protocol_websocket")] | ||||||
|     WebsocketError(tungstenite::Error), |     #[error("WebSocket error occurred while sending")] | ||||||
|  |     WebsocketError(#[from] tungstenite::Error), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Connection { | impl Connection { | ||||||
|  | @ -96,7 +92,7 @@ impl Connection { | ||||||
|     /// let uri = "ws://localhost:8080".parse().unwrap();
 |     /// let uri = "ws://localhost:8080".parse().unwrap();
 | ||||||
|     /// let mut connection = Connection::open_websocket(uri)
 |     /// let mut connection = Connection::open_websocket(uri)
 | ||||||
|     ///     .expect("could not connect");
 |     ///     .expect("could not connect");
 | ||||||
|     /// connection.send_mut(Command::Clear)
 |     /// connection.send(Command::Clear)
 | ||||||
|     ///     .expect("send failed");
 |     ///     .expect("send failed");
 | ||||||
|     /// ```
 |     /// ```
 | ||||||
|     #[cfg(feature = "protocol_websocket")] |     #[cfg(feature = "protocol_websocket")] | ||||||
|  | @ -111,25 +107,19 @@ impl Connection { | ||||||
| 
 | 
 | ||||||
|         let request = ClientRequestBuilder::new(uri).into_client_request()?; |         let request = ClientRequestBuilder::new(uri).into_client_request()?; | ||||||
|         let (sock, _) = connect(request)?; |         let (sock, _) = connect(request)?; | ||||||
|         Ok(Self::WebSocket(sock)) |         Ok(Self::WebSocket(std::sync::Mutex::new( | ||||||
|  |             sock, | ||||||
|  |         ))) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// 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.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// This variant can only be used for connections that support immutable send, e.g. [Connection::Udp].
 |  | ||||||
|     ///
 |  | ||||||
|     /// If you want to be able to switch the protocol, you should use [Self::send_mut] instead.
 |  | ||||||
|     ///
 |  | ||||||
|     /// # Arguments
 |     /// # Arguments
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// - `packet`: the packet-like to send
 |     /// - `packet`: the packet-like to send
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// returns: true if packet was sent, otherwise false
 |     /// returns: true if packet was sent, otherwise false
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// # Panics
 |  | ||||||
|     ///
 |  | ||||||
|     /// If the connection does not support immutable send, e.g. for [Connection::WebSocket].
 |  | ||||||
|     ///
 |  | ||||||
|     /// # Examples
 |     /// # Examples
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// ```rust
 |     /// ```rust
 | ||||||
|  | @ -150,59 +140,17 @@ impl Connection { | ||||||
|                     .map_err(SendError::IoError) |                     .map_err(SendError::IoError) | ||||||
|                     .map(move |_| ()) // ignore Ok value
 |                     .map(move |_| ()) // ignore Ok value
 | ||||||
|             } |             } | ||||||
|             Connection::Fake => { |  | ||||||
|                 let _ = data; |  | ||||||
|                 Ok(()) |  | ||||||
|             } |  | ||||||
|             #[allow(unreachable_patterns)] // depends on features
 |  | ||||||
|             _ => { |  | ||||||
|                 panic!("Connection {:?} does not support immutable send", self) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Send something packet-like to the display. Usually this is in the form of a Command.
 |  | ||||||
|     ///
 |  | ||||||
|     /// This variant has to be used for connections that do not support immutable send, e.g. [Connection::WebSocket].
 |  | ||||||
|     ///
 |  | ||||||
|     /// If you want to be able to switch the protocol, you should use this variant.
 |  | ||||||
|     ///
 |  | ||||||
|     /// # Arguments
 |  | ||||||
|     ///
 |  | ||||||
|     /// - `packet`: the packet-like to send
 |  | ||||||
|     ///
 |  | ||||||
|     /// returns: true if packet was sent, otherwise false
 |  | ||||||
|     ///
 |  | ||||||
|     /// # Examples
 |  | ||||||
|     ///
 |  | ||||||
|     /// ```rust
 |  | ||||||
|     ///  let mut connection = servicepoint::Connection::FakeMutableSend;
 |  | ||||||
|     ///  // turn off all pixels on display
 |  | ||||||
|     ///  connection.send_mut(servicepoint::Command::Clear)
 |  | ||||||
|     ///      .expect("send failed");
 |  | ||||||
|     /// ```
 |  | ||||||
|     pub fn send_mut( |  | ||||||
|         &mut self, |  | ||||||
|         packet: impl Into<Packet>, |  | ||||||
|     ) -> Result<(), SendError> { |  | ||||||
|         match self { |  | ||||||
|             #[cfg(feature = "protocol_websocket")] |             #[cfg(feature = "protocol_websocket")] | ||||||
|             Connection::WebSocket(socket) => { |             Connection::WebSocket(socket) => { | ||||||
|                 let packet = packet.into(); |                 let mut socket = socket.lock().unwrap(); | ||||||
|                 log::debug!("sending {packet:?}"); |  | ||||||
|                 let data: Vec<u8> = packet.into(); |  | ||||||
|                 socket |                 socket | ||||||
|                     .send(tungstenite::Message::Binary(data)) |                     .send(tungstenite::Message::Binary(data)) | ||||||
|                     .map_err(SendError::WebsocketError) |                     .map_err(SendError::WebsocketError) | ||||||
|             } |             } | ||||||
|             Connection::FakeMutableSend => { |             Connection::Fake => { | ||||||
|                 let packet = packet.into(); |  | ||||||
|                 log::debug!("sending {packet:?}"); |  | ||||||
|                 let data: Vec<u8> = packet.into(); |  | ||||||
|                 let _ = data; |                 let _ = data; | ||||||
|                 Ok(()) |                 Ok(()) | ||||||
|             } |             } | ||||||
|             _ => self.send(packet), |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -211,7 +159,9 @@ impl Drop for Connection { | ||||||
|     fn drop(&mut self) { |     fn drop(&mut self) { | ||||||
|         #[cfg(feature = "protocol_websocket")] |         #[cfg(feature = "protocol_websocket")] | ||||||
|         if let Connection::WebSocket(sock) = self { |         if let Connection::WebSocket(sock) = self { | ||||||
|             _ = sock.close(None); |             _ = sock | ||||||
|  |                 .try_lock() | ||||||
|  |                 .map(move |mut sock| sock.close(None)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -227,19 +177,4 @@ mod tests { | ||||||
|         let packet = Packet::try_from(data).unwrap(); |         let packet = Packet::try_from(data).unwrap(); | ||||||
|         Connection::Fake.send(packet).unwrap() |         Connection::Fake.send(packet).unwrap() | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     #[test] |  | ||||||
|     fn send_fake_mutable() { |  | ||||||
|         let data: &[u8] = &[0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; |  | ||||||
|         let packet = Packet::try_from(data).unwrap(); |  | ||||||
|         Connection::FakeMutableSend.send_mut(packet).unwrap() |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     #[test] |  | ||||||
|     #[should_panic] |  | ||||||
|     fn send_fake_mutable_panic() { |  | ||||||
|         let data: &[u8] = &[0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; |  | ||||||
|         let packet = Packet::try_from(data).unwrap(); |  | ||||||
|         Connection::FakeMutableSend.send(packet).unwrap() |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -10,19 +10,14 @@ use std::collections::HashMap; | ||||||
| /// The encoding is currently not enforced.
 | /// The encoding is currently not enforced.
 | ||||||
| pub type Cp437Grid = PrimitiveGrid<u8>; | pub type Cp437Grid = PrimitiveGrid<u8>; | ||||||
| 
 | 
 | ||||||
| /// A grid containing UTF-8 characters.
 | /// The error occurring when loading an invalid character
 | ||||||
| pub type CharGrid = PrimitiveGrid<char>; | #[derive(Debug, PartialEq, thiserror::Error)] | ||||||
| 
 | #[error("The character {char:?} at position {index} is not a valid CP437 character")] | ||||||
| /// Errors that can occur when loading CP-437.
 | pub struct InvalidCharError { | ||||||
| #[derive(Debug, PartialEq)] |     /// invalid character is at this position in input
 | ||||||
| pub enum Cp437LoadError { |     index: usize, | ||||||
|     /// Invalid character in input prevented loading
 |     /// the invalid character
 | ||||||
|     InvalidChar { |     char: char, | ||||||
|         /// invalid character is at this position in input
 |  | ||||||
|         index: usize, |  | ||||||
|         /// the invalid character
 |  | ||||||
|         char: char, |  | ||||||
|     }, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Cp437Grid { | impl Cp437Grid { | ||||||
|  | @ -36,7 +31,7 @@ impl Cp437Grid { | ||||||
|         value: &str, |         value: &str, | ||||||
|         width: usize, |         width: usize, | ||||||
|         wrap: bool, |         wrap: bool, | ||||||
|     ) -> Result<Self, Cp437LoadError> { |     ) -> Result<Self, InvalidCharError> { | ||||||
|         assert!(width > 0); |         assert!(width > 0); | ||||||
|         assert!(!value.is_empty()); |         assert!(!value.is_empty()); | ||||||
| 
 | 
 | ||||||
|  | @ -46,7 +41,7 @@ impl Cp437Grid { | ||||||
| 
 | 
 | ||||||
|             for (index, char) in value.chars().enumerate() { |             for (index, char) in value.chars().enumerate() { | ||||||
|                 if !char.is_ascii() { |                 if !char.is_ascii() { | ||||||
|                     return Err(Cp437LoadError::InvalidChar { index, char }); |                     return Err(InvalidCharError { index, char }); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 let is_lf = char == '\n'; |                 let is_lf = char == '\n'; | ||||||
|  | @ -92,6 +87,7 @@ pub use feature_cp437::*; | ||||||
| #[cfg(feature = "cp437")] | #[cfg(feature = "cp437")] | ||||||
| mod feature_cp437 { | mod feature_cp437 { | ||||||
|     use super::*; |     use super::*; | ||||||
|  |     use crate::CharGrid; | ||||||
| 
 | 
 | ||||||
|     /// An array of 256 elements, mapping most of the CP437 values to UTF-8 characters
 |     /// An array of 256 elements, mapping most of the CP437 values to UTF-8 characters
 | ||||||
|     ///
 |     ///
 | ||||||
|  | @ -99,7 +95,7 @@ mod feature_cp437 { | ||||||
|     ///
 |     ///
 | ||||||
|     /// See <https://en.wikipedia.org/wiki/Code_page_437#Character_set>
 |     /// See <https://en.wikipedia.org/wiki/Code_page_437#Character_set>
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// Mostly copied from https://github.com/kip93/cp437-tools. License: GPL-3.0
 |     /// Mostly copied from <https://github.com/kip93/cp437-tools>. License: GPL-3.0
 | ||||||
|     #[rustfmt::skip] |     #[rustfmt::skip] | ||||||
|     pub const CP437_TO_UTF8: [char; 256] = [ |     pub const CP437_TO_UTF8: [char; 256] = [ | ||||||
|         /* 0X */ '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '\n', '♂', '♀', '♪', '♫', '☼', |         /* 0X */ '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '\n', '♂', '♀', '♪', '♫', '☼', | ||||||
|  | @ -143,44 +139,9 @@ mod feature_cp437 { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     impl From<&str> for CharGrid { |     impl From<CharGrid> for Cp437Grid { | ||||||
|         fn from(value: &str) -> Self { |         fn from(value: CharGrid) -> Self { | ||||||
|             let value = value.replace("\r\n", "\n"); |             Cp437Grid::from(&value) | ||||||
|             let mut lines = value |  | ||||||
|                 .split('\n') |  | ||||||
|                 .map(move |line| line.trim_end()) |  | ||||||
|                 .collect::<Vec<_>>(); |  | ||||||
|             let width = |  | ||||||
|                 lines.iter().fold(0, move |a, x| std::cmp::max(a, x.len())); |  | ||||||
| 
 |  | ||||||
|             while lines.last().is_some_and(move |line| line.is_empty()) { |  | ||||||
|                 _ = lines.pop(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             let mut grid = Self::new(width, lines.len()); |  | ||||||
|             for (y, line) in lines.iter().enumerate() { |  | ||||||
|                 for (x, char) in line.chars().enumerate() { |  | ||||||
|                     grid.set(x, y, char); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             grid |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     impl From<&CharGrid> for String { |  | ||||||
|         fn from(value: &CharGrid) -> Self { |  | ||||||
|             value |  | ||||||
|                 .iter_rows() |  | ||||||
|                 .map(move |chars| { |  | ||||||
|                     chars |  | ||||||
|                         .collect::<String>() |  | ||||||
|                         .replace('\0', " ") |  | ||||||
|                         .trim_end() |  | ||||||
|                         .to_string() |  | ||||||
|                 }) |  | ||||||
|                 .collect::<Vec<_>>() |  | ||||||
|                 .join("\n") |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -236,7 +197,7 @@ mod tests { | ||||||
|     #[test] |     #[test] | ||||||
|     fn load_ascii_invalid() { |     fn load_ascii_invalid() { | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
|             Err(Cp437LoadError::InvalidChar { |             Err(InvalidCharError { | ||||||
|                 char: '🥶', |                 char: '🥶', | ||||||
|                 index: 2 |                 index: 2 | ||||||
|             }), |             }), | ||||||
|  | @ -249,6 +210,7 @@ mod tests { | ||||||
| #[cfg(feature = "cp437")] | #[cfg(feature = "cp437")] | ||||||
| mod tests_feature_cp437 { | mod tests_feature_cp437 { | ||||||
|     use super::*; |     use super::*; | ||||||
|  |     use crate::CharGrid; | ||||||
| 
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn round_trip_cp437() { |     fn round_trip_cp437() { | ||||||
|  | @ -292,13 +254,4 @@ mod tests_feature_cp437 { | ||||||
|     fn convert_invalid() { |     fn convert_invalid() { | ||||||
|         assert_eq!(cp437_to_char(char_to_cp437('😜')), '?'); |         assert_eq!(cp437_to_char(char_to_cp437('😜')), '?'); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     #[test] |  | ||||||
|     fn str_to_char_grid() { |  | ||||||
|         let original = "Hello\r\nWorld!\n...\n"; |  | ||||||
|         let grid = CharGrid::from(original); |  | ||||||
|         assert_eq!(3, grid.height()); |  | ||||||
|         let actual = String::from(&grid); |  | ||||||
|         assert_eq!("Hello\nWorld!\n...", actual); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -38,23 +38,25 @@ | ||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
| 
 | 
 | ||||||
| pub use bitvec; | pub use bitvec; | ||||||
| use bitvec::prelude::{BitVec, Msb0}; |  | ||||||
| 
 | 
 | ||||||
| pub use crate::bitmap::Bitmap; | pub use crate::bitmap::Bitmap; | ||||||
| pub use crate::brightness::{Brightness, BrightnessGrid}; | pub use crate::brightness::{Brightness, BrightnessGrid}; | ||||||
|  | pub use crate::char_grid::CharGrid; | ||||||
| pub use crate::command::{Command, Offset}; | pub use crate::command::{Command, Offset}; | ||||||
| pub use crate::compression_code::CompressionCode; | pub use crate::compression_code::CompressionCode; | ||||||
| pub use crate::connection::Connection; | pub use crate::connection::Connection; | ||||||
| pub use crate::cp437::{CharGrid, Cp437Grid}; | pub use crate::cp437::Cp437Grid; | ||||||
| pub use crate::data_ref::DataRef; | pub use crate::data_ref::DataRef; | ||||||
| pub use crate::grid::Grid; | pub use crate::grid::Grid; | ||||||
| pub use crate::origin::{Origin, Pixels, Tiles}; | pub use crate::origin::{Origin, Pixels, Tiles}; | ||||||
| pub use crate::primitive_grid::PrimitiveGrid; | pub use crate::primitive_grid::{PrimitiveGrid, SeriesError}; | ||||||
| 
 | 
 | ||||||
| type SpBitVec = BitVec<u8, Msb0>; | /// An alias for the specific type of [bitvec::prelude::BitVec] used.
 | ||||||
|  | pub type BitVec = bitvec::prelude::BitVec<u8, bitvec::prelude::Msb0>; | ||||||
| 
 | 
 | ||||||
| mod bitmap; | mod bitmap; | ||||||
| mod brightness; | mod brightness; | ||||||
|  | mod char_grid; | ||||||
| mod command; | mod command; | ||||||
| mod command_code; | mod command_code; | ||||||
| mod compression; | mod compression; | ||||||
|  |  | ||||||
|  | @ -13,6 +13,27 @@ pub struct PrimitiveGrid<T: PrimitiveGridType> { | ||||||
|     data: Vec<T>, |     data: Vec<T>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Error type for methods that change a whole column or row at once
 | ||||||
|  | #[derive(thiserror::Error, Debug, PartialEq)] | ||||||
|  | pub enum SeriesError { | ||||||
|  |     #[error("The index {index} was out of bounds for size {size}")] | ||||||
|  |     /// The index {index} was out of bounds for size {size}
 | ||||||
|  |     OutOfBounds { | ||||||
|  |         /// the index where access was tried
 | ||||||
|  |         index: usize, | ||||||
|  |         /// the size in that direction
 | ||||||
|  |         size: usize, | ||||||
|  |     }, | ||||||
|  |     #[error("The provided series was expected to have a length of {expected}, but was {actual}")] | ||||||
|  |     /// The provided series was expected to have a length of {expected}, but was {actual}
 | ||||||
|  |     InvalidLength { | ||||||
|  |         /// actual size of the provided series
 | ||||||
|  |         actual: usize, | ||||||
|  |         /// expected size
 | ||||||
|  |         expected: usize, | ||||||
|  |     }, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl<T: PrimitiveGridType> PrimitiveGrid<T> { | impl<T: PrimitiveGridType> PrimitiveGrid<T> { | ||||||
|     /// Creates a new [PrimitiveGrid] with the specified dimensions.
 |     /// Creates a new [PrimitiveGrid] with the specified dimensions.
 | ||||||
|     ///
 |     ///
 | ||||||
|  | @ -126,6 +147,8 @@ impl<T: PrimitiveGridType> PrimitiveGrid<T> { | ||||||
|     /// let grid: BrightnessGrid = grid.map(Brightness::saturating_from);
 |     /// let grid: BrightnessGrid = grid.map(Brightness::saturating_from);
 | ||||||
|     /// let command = Command::CharBrightness(Origin::ZERO, grid);
 |     /// let command = Command::CharBrightness(Origin::ZERO, grid);
 | ||||||
|     /// ```
 |     /// ```
 | ||||||
|  |     /// [Brightness]: [crate::Brightness]
 | ||||||
|  |     /// [Command]: [crate::Command]
 | ||||||
|     pub fn map<TConverted, F>(&self, f: F) -> PrimitiveGrid<TConverted> |     pub fn map<TConverted, F>(&self, f: F) -> PrimitiveGrid<TConverted> | ||||||
|     where |     where | ||||||
|         TConverted: PrimitiveGridType, |         TConverted: PrimitiveGridType, | ||||||
|  | @ -138,6 +161,81 @@ impl<T: PrimitiveGridType> PrimitiveGrid<T> { | ||||||
|             .collect::<Vec<_>>(); |             .collect::<Vec<_>>(); | ||||||
|         PrimitiveGrid::load(self.width(), self.height(), &data) |         PrimitiveGrid::load(self.width(), self.height(), &data) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /// Copies a row from the grid.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Returns [None] if y is out of bounds.
 | ||||||
|  |     pub fn get_row(&self, y: usize) -> Option<Vec<T>> { | ||||||
|  |         self.data | ||||||
|  |             .chunks_exact(self.width()) | ||||||
|  |             .nth(y) | ||||||
|  |             .map(|row| row.to_vec()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Copies a column from the grid.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Returns [None] if x is out of bounds.
 | ||||||
|  |     pub fn get_col(&self, x: usize) -> Option<Vec<T>> { | ||||||
|  |         self.data | ||||||
|  |             .chunks_exact(self.width()) | ||||||
|  |             .map(|row| row.get(x).copied()) | ||||||
|  |             .collect() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Overwrites a column in the grid.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Returns [Err] if x is out of bounds or `col` is not of the correct size.
 | ||||||
|  |     pub fn set_col(&mut self, x: usize, col: &[T]) -> Result<(), SeriesError> { | ||||||
|  |         if col.len() != self.height() { | ||||||
|  |             return Err(SeriesError::InvalidLength { | ||||||
|  |                 expected: self.height(), | ||||||
|  |                 actual: col.len(), | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |         let width = self.width(); | ||||||
|  |         if self | ||||||
|  |             .data | ||||||
|  |             .chunks_exact_mut(width) | ||||||
|  |             .zip(col.iter()) | ||||||
|  |             .map(|(row, column_value)| { | ||||||
|  |                 row.get_mut(x).map(move |cell| *cell = *column_value) | ||||||
|  |             }) | ||||||
|  |             .all(|cell| cell.is_some()) | ||||||
|  |         { | ||||||
|  |             Ok(()) | ||||||
|  |         } else { | ||||||
|  |             Err(SeriesError::OutOfBounds { | ||||||
|  |                 index: x, | ||||||
|  |                 size: width, | ||||||
|  |             }) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Overwrites a row in the grid.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Returns [Err] if y is out of bounds or `row` is not of the correct size.
 | ||||||
|  |     pub fn set_row(&mut self, y: usize, row: &[T]) -> Result<(), SeriesError> { | ||||||
|  |         let width = self.width(); | ||||||
|  |         if row.len() != width { | ||||||
|  |             return Err(SeriesError::InvalidLength { | ||||||
|  |                 expected: width, | ||||||
|  |                 actual: row.len(), | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let chunk = match self.data.chunks_exact_mut(width).nth(y) { | ||||||
|  |             Some(row) => row, | ||||||
|  |             None => { | ||||||
|  |                 return Err(SeriesError::OutOfBounds { | ||||||
|  |                     size: self.height(), | ||||||
|  |                     index: y, | ||||||
|  |                 }) | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         chunk.copy_from_slice(row); | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: PrimitiveGridType> Grid<T> for PrimitiveGrid<T> { | impl<T: PrimitiveGridType> Grid<T> for PrimitiveGrid<T> { | ||||||
|  | @ -225,7 +323,7 @@ impl<'t, T: PrimitiveGridType> Iterator for IterRows<'t, T> { | ||||||
| 
 | 
 | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     use crate::{DataRef, Grid, PrimitiveGrid}; |     use crate::{DataRef, Grid, PrimitiveGrid, SeriesError}; | ||||||
| 
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn fill() { |     fn fill() { | ||||||
|  | @ -347,4 +445,46 @@ mod tests { | ||||||
|         assert_eq!(grid.get_optional(0, 0), Some(5)); |         assert_eq!(grid.get_optional(0, 0), Some(5)); | ||||||
|         assert_eq!(grid.get_optional(0, 8), None); |         assert_eq!(grid.get_optional(0, 8), None); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn col() { | ||||||
|  |         let mut grid = PrimitiveGrid::load(2, 3, &[0, 1, 2, 3, 4, 5]); | ||||||
|  |         assert_eq!(grid.get_col(0), Some(vec![0, 2, 4])); | ||||||
|  |         assert_eq!(grid.get_col(1), Some(vec![1, 3, 5])); | ||||||
|  |         assert_eq!(grid.get_col(2), None); | ||||||
|  |         assert_eq!(grid.set_col(0, &[5, 7, 9]), Ok(())); | ||||||
|  |         assert_eq!( | ||||||
|  |             grid.set_col(2, &[5, 7, 9]), | ||||||
|  |             Err(SeriesError::OutOfBounds { size: 2, index: 2 }) | ||||||
|  |         ); | ||||||
|  |         assert_eq!( | ||||||
|  |             grid.set_col(0, &[5, 7]), | ||||||
|  |             Err(SeriesError::InvalidLength { | ||||||
|  |                 expected: 3, | ||||||
|  |                 actual: 2 | ||||||
|  |             }) | ||||||
|  |         ); | ||||||
|  |         assert_eq!(grid.get_col(0), Some(vec![5, 7, 9])); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn row() { | ||||||
|  |         let mut grid = PrimitiveGrid::load(2, 3, &[0, 1, 2, 3, 4, 5]); | ||||||
|  |         assert_eq!(grid.get_row(0), Some(vec![0, 1])); | ||||||
|  |         assert_eq!(grid.get_row(2), Some(vec![4, 5])); | ||||||
|  |         assert_eq!(grid.get_row(3), None); | ||||||
|  |         assert_eq!(grid.set_row(0, &[5, 7]), Ok(())); | ||||||
|  |         assert_eq!(grid.get_row(0), Some(vec![5, 7])); | ||||||
|  |         assert_eq!( | ||||||
|  |             grid.set_row(3, &[5, 7]), | ||||||
|  |             Err(SeriesError::OutOfBounds { size: 3, index: 3 }) | ||||||
|  |         ); | ||||||
|  |         assert_eq!( | ||||||
|  |             grid.set_row(2, &[5, 7, 3]), | ||||||
|  |             Err(SeriesError::InvalidLength { | ||||||
|  |                 expected: 2, | ||||||
|  |                 actual: 3 | ||||||
|  |             }) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ crate-type = ["staticlib", "cdylib", "rlib"] | ||||||
| cbindgen = "0.27.0" | cbindgen = "0.27.0" | ||||||
| 
 | 
 | ||||||
| [dependencies.servicepoint] | [dependencies.servicepoint] | ||||||
| version = "0.10.0" | version = "0.11.0" | ||||||
| path = "../servicepoint" | path = "../servicepoint" | ||||||
| features = ["all_compressions"] | features = ["all_compressions"] | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -144,6 +144,8 @@ typedef struct SPBrightnessGrid SPBrightnessGrid; | ||||||
|  * sp_connection_send_command(connection, sp_command_clear()); |  * sp_connection_send_command(connection, sp_command_clear()); | ||||||
|  * sp_connection_send_command(connection, sp_command_brightness(5)); |  * sp_connection_send_command(connection, sp_command_brightness(5)); | ||||||
|  * ``` |  * ``` | ||||||
|  |  * | ||||||
|  |  * [SPConnection]: [crate::SPConnection] | ||||||
|  */ |  */ | ||||||
| typedef struct SPCommand SPCommand; | typedef struct SPCommand SPCommand; | ||||||
| 
 | 
 | ||||||
|  | @ -266,6 +268,8 @@ void sp_bitmap_fill(SPBitmap *bitmap, bool value); | ||||||
|  * - `bitmap` points to a valid [SPBitmap] |  * - `bitmap` points to a valid [SPBitmap] | ||||||
|  * - `bitmap` is not used concurrently or after bitmap call |  * - `bitmap` is not used concurrently or after bitmap call | ||||||
|  * - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] |  * - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] | ||||||
|  |  * | ||||||
|  |  * [SPCommand]: [crate::SPCommand] | ||||||
|  */ |  */ | ||||||
| void sp_bitmap_free(SPBitmap *bitmap); | void sp_bitmap_free(SPBitmap *bitmap); | ||||||
| 
 | 
 | ||||||
|  | @ -479,6 +483,8 @@ void sp_bitvec_fill(SPBitVec *bit_vec, bool value); | ||||||
|  * - `bit_vec` points to a valid [SPBitVec] |  * - `bit_vec` points to a valid [SPBitVec] | ||||||
|  * - `bit_vec` is not used concurrently or after this call |  * - `bit_vec` is not used concurrently or after this call | ||||||
|  * - `bit_vec` was not passed to another consuming function, e.g. to create a [SPCommand] |  * - `bit_vec` was not passed to another consuming function, e.g. to create a [SPCommand] | ||||||
|  |  * | ||||||
|  |  * [SPCommand]: [crate::SPCommand] | ||||||
|  */ |  */ | ||||||
| void sp_bitvec_free(SPBitVec *bit_vec); | void sp_bitvec_free(SPBitVec *bit_vec); | ||||||
| 
 | 
 | ||||||
|  | @ -695,6 +701,8 @@ void sp_brightness_grid_fill(SPBrightnessGrid *brightness_grid, uint8_t value); | ||||||
|  * - `brightness_grid` points to a valid [SPBrightnessGrid] |  * - `brightness_grid` points to a valid [SPBrightnessGrid] | ||||||
|  * - `brightness_grid` is not used concurrently or after this call |  * - `brightness_grid` is not used concurrently or after this call | ||||||
|  * - `brightness_grid` was not passed to another consuming function, e.g. to create a [SPCommand] |  * - `brightness_grid` was not passed to another consuming function, e.g. to create a [SPCommand] | ||||||
|  |  * | ||||||
|  |  * [SPCommand]: [crate::SPCommand] | ||||||
|  */ |  */ | ||||||
| void sp_brightness_grid_free(SPBrightnessGrid *brightness_grid); | void sp_brightness_grid_free(SPBrightnessGrid *brightness_grid); | ||||||
| 
 | 
 | ||||||
|  | @ -805,7 +813,7 @@ SPBrightnessGrid *sp_brightness_grid_new(size_t width, | ||||||
|  * |  * | ||||||
|  * The caller has to make sure that: |  * The caller has to make sure that: | ||||||
|  * |  * | ||||||
|  * - `brightness_grid` points to a valid [SPBitVec] |  * - `brightness_grid` points to a valid [SPBrightnessGrid] | ||||||
|  * - `brightness_grid` is not written to or read from concurrently |  * - `brightness_grid` is not written to or read from concurrently | ||||||
|  */ |  */ | ||||||
| void sp_brightness_grid_set(SPBrightnessGrid *brightness_grid, | void sp_brightness_grid_set(SPBrightnessGrid *brightness_grid, | ||||||
|  | @ -867,7 +875,7 @@ size_t sp_brightness_grid_width(const SPBrightnessGrid *brightness_grid); | ||||||
|  * |  * | ||||||
|  * The passed [SPBitVec] gets consumed. |  * The passed [SPBitVec] gets consumed. | ||||||
|  * |  * | ||||||
|  * Returns: a new [Command::BitmapLinear] instance. Will never return NULL. |  * Returns: a new [servicepoint::Command::BitmapLinear] instance. Will never return NULL. | ||||||
|  * |  * | ||||||
|  * # Panics |  * # Panics | ||||||
|  * |  * | ||||||
|  | @ -898,7 +906,7 @@ SPCommand *sp_command_bitmap_linear(size_t offset, | ||||||
|  * |  * | ||||||
|  * The passed [SPBitVec] gets consumed. |  * The passed [SPBitVec] gets consumed. | ||||||
|  * |  * | ||||||
|  * Returns: a new [Command::BitmapLinearAnd] instance. Will never return NULL. |  * Returns: a new [servicepoint::Command::BitmapLinearAnd] instance. Will never return NULL. | ||||||
|  * |  * | ||||||
|  * # Panics |  * # Panics | ||||||
|  * |  * | ||||||
|  | @ -929,7 +937,7 @@ SPCommand *sp_command_bitmap_linear_and(size_t offset, | ||||||
|  * |  * | ||||||
|  * The passed [SPBitVec] gets consumed. |  * The passed [SPBitVec] gets consumed. | ||||||
|  * |  * | ||||||
|  * Returns: a new [Command::BitmapLinearOr] instance. Will never return NULL. |  * Returns: a new [servicepoint::Command::BitmapLinearOr] instance. Will never return NULL. | ||||||
|  * |  * | ||||||
|  * # Panics |  * # Panics | ||||||
|  * |  * | ||||||
|  | @ -955,7 +963,7 @@ SPCommand *sp_command_bitmap_linear_or(size_t offset, | ||||||
|  * |  * | ||||||
|  * The passed [SPBitmap] gets consumed. |  * The passed [SPBitmap] gets consumed. | ||||||
|  * |  * | ||||||
|  * Returns: a new [Command::BitmapLinearWin] instance. Will never return NULL. |  * Returns: a new [servicepoint::Command::BitmapLinearWin] instance. Will never return NULL. | ||||||
|  * |  * | ||||||
|  * # Panics |  * # Panics | ||||||
|  * |  * | ||||||
|  | @ -987,7 +995,7 @@ SPCommand *sp_command_bitmap_linear_win(size_t x, | ||||||
|  * |  * | ||||||
|  * The passed [SPBitVec] gets consumed. |  * The passed [SPBitVec] gets consumed. | ||||||
|  * |  * | ||||||
|  * Returns: a new [Command::BitmapLinearXor] instance. Will never return NULL. |  * Returns: a new [servicepoint::Command::BitmapLinearXor] instance. Will never return NULL. | ||||||
|  * |  * | ||||||
|  * # Panics |  * # Panics | ||||||
|  * |  * | ||||||
|  | @ -1011,7 +1019,7 @@ SPCommand *sp_command_bitmap_linear_xor(size_t offset, | ||||||
| /**
 | /**
 | ||||||
|  * Set the brightness of all tiles to the same value. |  * Set the brightness of all tiles to the same value. | ||||||
|  * |  * | ||||||
|  * Returns: a new [Command::Brightness] instance. Will never return NULL. |  * Returns: a new [servicepoint::Command::Brightness] instance. Will never return NULL. | ||||||
|  * |  * | ||||||
|  * # Panics |  * # Panics | ||||||
|  * |  * | ||||||
|  | @ -1031,7 +1039,7 @@ SPCommand *sp_command_brightness(uint8_t brightness); | ||||||
|  * |  * | ||||||
|  * The passed [SPBrightnessGrid] gets consumed. |  * The passed [SPBrightnessGrid] gets consumed. | ||||||
|  * |  * | ||||||
|  * Returns: a new [Command::CharBrightness] instance. Will never return NULL. |  * Returns: a new [servicepoint::Command::CharBrightness] instance. Will never return NULL. | ||||||
|  * |  * | ||||||
|  * # Panics |  * # Panics | ||||||
|  * |  * | ||||||
|  | @ -1055,7 +1063,7 @@ SPCommand *sp_command_char_brightness(size_t x, | ||||||
|  * |  * | ||||||
|  * Does not affect brightness. |  * Does not affect brightness. | ||||||
|  * |  * | ||||||
|  * Returns: a new [Command::Clear] instance. Will never return NULL. |  * Returns: a new [servicepoint::Command::Clear] instance. Will never return NULL. | ||||||
|  * |  * | ||||||
|  * # Examples |  * # Examples | ||||||
|  * |  * | ||||||
|  | @ -1097,7 +1105,7 @@ SPCommand *sp_command_clone(const SPCommand *command); | ||||||
|  * |  * | ||||||
|  * The passed [SPCp437Grid] gets consumed. |  * The passed [SPCp437Grid] gets consumed. | ||||||
|  * |  * | ||||||
|  * Returns: a new [Command::Cp437Data] instance. Will never return NULL. |  * Returns: a new [servicepoint::Command::Cp437Data] instance. Will never return NULL. | ||||||
|  * |  * | ||||||
|  * # Panics |  * # Panics | ||||||
|  * |  * | ||||||
|  | @ -1119,7 +1127,7 @@ SPCommand *sp_command_cp437_data(size_t x, | ||||||
| /**
 | /**
 | ||||||
|  * A yet-to-be-tested command. |  * A yet-to-be-tested command. | ||||||
|  * |  * | ||||||
|  * Returns: a new `Command::FadeOut` instance. Will never return NULL. |  * Returns: a new [servicepoint::Command::FadeOut] instance. Will never return NULL. | ||||||
|  * |  * | ||||||
|  * # Safety |  * # Safety | ||||||
|  * |  * | ||||||
|  | @ -1159,7 +1167,7 @@ void sp_command_free(SPCommand *command); | ||||||
|  * |  * | ||||||
|  * Please do not send this in your normal program flow. |  * Please do not send this in your normal program flow. | ||||||
|  * |  * | ||||||
|  * Returns: a new [Command::HardReset] instance. Will never return NULL. |  * Returns: a new [servicepoint::Command::HardReset] instance. Will never return NULL. | ||||||
|  * |  * | ||||||
|  * # Safety |  * # Safety | ||||||
|  * |  * | ||||||
|  | @ -1328,6 +1336,8 @@ void sp_cp437_grid_fill(SPCp437Grid *cp437_grid, uint8_t value); | ||||||
|  * - `cp437_grid` points to a valid [SPCp437Grid] |  * - `cp437_grid` points to a valid [SPCp437Grid] | ||||||
|  * - `cp437_grid` is not used concurrently or after cp437_grid call |  * - `cp437_grid` is not used concurrently or after cp437_grid call | ||||||
|  * - `cp437_grid` was not passed to another consuming function, e.g. to create a [SPCommand] |  * - `cp437_grid` was not passed to another consuming function, e.g. to create a [SPCommand] | ||||||
|  |  * | ||||||
|  |  * [SPCommand]: [crate::SPCommand] | ||||||
|  */ |  */ | ||||||
| void sp_cp437_grid_free(SPCp437Grid *cp437_grid); | void sp_cp437_grid_free(SPCp437Grid *cp437_grid); | ||||||
| 
 | 
 | ||||||
|  | @ -1433,6 +1443,8 @@ SPCp437Grid *sp_cp437_grid_new(size_t width, | ||||||
|  * |  * | ||||||
|  * - `cp437_grid` points to a valid [SPBitVec] |  * - `cp437_grid` points to a valid [SPBitVec] | ||||||
|  * - `cp437_grid` is not written to or read from concurrently |  * - `cp437_grid` is not written to or read from concurrently | ||||||
|  |  * | ||||||
|  |  * [SPBitVec]: [crate::SPBitVec] | ||||||
|  */ |  */ | ||||||
| void sp_cp437_grid_set(SPCp437Grid *cp437_grid, | void sp_cp437_grid_set(SPCp437Grid *cp437_grid, | ||||||
|                        size_t x, |                        size_t x, | ||||||
|  |  | ||||||
|  | @ -124,6 +124,8 @@ pub unsafe extern "C" fn sp_bitmap_clone( | ||||||
| /// - `bitmap` points to a valid [SPBitmap]
 | /// - `bitmap` points to a valid [SPBitmap]
 | ||||||
| /// - `bitmap` is not used concurrently or after bitmap call
 | /// - `bitmap` is not used concurrently or after bitmap call
 | ||||||
| /// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand]
 | /// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand]
 | ||||||
|  | ///
 | ||||||
|  | /// [SPCommand]: [crate::SPCommand]
 | ||||||
| #[no_mangle] | #[no_mangle] | ||||||
| pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) { | pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut SPBitmap) { | ||||||
|     assert!(!bitmap.is_null()); |     assert!(!bitmap.is_null()); | ||||||
|  |  | ||||||
|  | @ -123,6 +123,8 @@ pub unsafe extern "C" fn sp_bitvec_clone( | ||||||
| /// - `bit_vec` points to a valid [SPBitVec]
 | /// - `bit_vec` points to a valid [SPBitVec]
 | ||||||
| /// - `bit_vec` is not used concurrently or after this call
 | /// - `bit_vec` is not used concurrently or after this call
 | ||||||
| /// - `bit_vec` was not passed to another consuming function, e.g. to create a [SPCommand]
 | /// - `bit_vec` was not passed to another consuming function, e.g. to create a [SPCommand]
 | ||||||
|  | ///
 | ||||||
|  | /// [SPCommand]: [crate::SPCommand]
 | ||||||
| #[no_mangle] | #[no_mangle] | ||||||
| pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) { | pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) { | ||||||
|     assert!(!bit_vec.is_null()); |     assert!(!bit_vec.is_null()); | ||||||
|  |  | ||||||
|  | @ -133,6 +133,8 @@ pub unsafe extern "C" fn sp_brightness_grid_clone( | ||||||
| /// - `brightness_grid` points to a valid [SPBrightnessGrid]
 | /// - `brightness_grid` points to a valid [SPBrightnessGrid]
 | ||||||
| /// - `brightness_grid` is not used concurrently or after this call
 | /// - `brightness_grid` is not used concurrently or after this call
 | ||||||
| /// - `brightness_grid` was not passed to another consuming function, e.g. to create a [SPCommand]
 | /// - `brightness_grid` was not passed to another consuming function, e.g. to create a [SPCommand]
 | ||||||
|  | ///
 | ||||||
|  | /// [SPCommand]: [crate::SPCommand]
 | ||||||
| #[no_mangle] | #[no_mangle] | ||||||
| pub unsafe extern "C" fn sp_brightness_grid_free( | pub unsafe extern "C" fn sp_brightness_grid_free( | ||||||
|     brightness_grid: *mut SPBrightnessGrid, |     brightness_grid: *mut SPBrightnessGrid, | ||||||
|  | @ -191,7 +193,7 @@ pub unsafe extern "C" fn sp_brightness_grid_get( | ||||||
| ///
 | ///
 | ||||||
| /// The caller has to make sure that:
 | /// The caller has to make sure that:
 | ||||||
| ///
 | ///
 | ||||||
| /// - `brightness_grid` points to a valid [SPBitVec]
 | /// - `brightness_grid` points to a valid [SPBrightnessGrid]
 | ||||||
| /// - `brightness_grid` 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( | ||||||
|  |  | ||||||
|  | @ -23,6 +23,8 @@ use crate::{ | ||||||
| /// sp_connection_send_command(connection, sp_command_clear());
 | /// sp_connection_send_command(connection, sp_command_clear());
 | ||||||
| /// sp_connection_send_command(connection, sp_command_brightness(5));
 | /// sp_connection_send_command(connection, sp_command_brightness(5));
 | ||||||
| /// ```
 | /// ```
 | ||||||
|  | ///
 | ||||||
|  | /// [SPConnection]: [crate::SPConnection]
 | ||||||
| pub struct SPCommand(pub(crate) servicepoint::Command); | pub struct SPCommand(pub(crate) servicepoint::Command); | ||||||
| 
 | 
 | ||||||
| impl Clone for SPCommand { | impl Clone for SPCommand { | ||||||
|  | @ -90,7 +92,7 @@ pub unsafe extern "C" fn sp_command_clone( | ||||||
| ///
 | ///
 | ||||||
| /// Does not affect brightness.
 | /// Does not affect brightness.
 | ||||||
| ///
 | ///
 | ||||||
| /// Returns: a new [Command::Clear] instance. Will never return NULL.
 | /// Returns: a new [servicepoint::Command::Clear] instance. Will never return NULL.
 | ||||||
| ///
 | ///
 | ||||||
| /// # Examples
 | /// # Examples
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -114,7 +116,7 @@ pub unsafe extern "C" fn sp_command_clear() -> NonNull<SPCommand> { | ||||||
| ///
 | ///
 | ||||||
| /// Please do not send this in your normal program flow.
 | /// Please do not send this in your normal program flow.
 | ||||||
| ///
 | ///
 | ||||||
| /// Returns: a new [Command::HardReset] instance. Will never return NULL.
 | /// Returns: a new [servicepoint::Command::HardReset] instance. Will never return NULL.
 | ||||||
| ///
 | ///
 | ||||||
| /// # Safety
 | /// # Safety
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -130,7 +132,7 @@ pub unsafe extern "C" fn sp_command_hard_reset() -> NonNull<SPCommand> { | ||||||
| 
 | 
 | ||||||
| /// A yet-to-be-tested command.
 | /// A yet-to-be-tested command.
 | ||||||
| ///
 | ///
 | ||||||
| /// Returns: a new `Command::FadeOut` instance. Will never return NULL.
 | /// Returns: a new [servicepoint::Command::FadeOut] instance. Will never return NULL.
 | ||||||
| ///
 | ///
 | ||||||
| /// # Safety
 | /// # Safety
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -146,7 +148,7 @@ pub unsafe extern "C" fn sp_command_fade_out() -> NonNull<SPCommand> { | ||||||
| 
 | 
 | ||||||
| /// Set the brightness of all tiles to the same value.
 | /// Set the brightness of all tiles to the same value.
 | ||||||
| ///
 | ///
 | ||||||
| /// Returns: a new [Command::Brightness] instance. Will never return NULL.
 | /// Returns: a new [servicepoint::Command::Brightness] instance. Will never return NULL.
 | ||||||
| ///
 | ///
 | ||||||
| /// # Panics
 | /// # Panics
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -174,7 +176,7 @@ pub unsafe extern "C" fn sp_command_brightness( | ||||||
| ///
 | ///
 | ||||||
| /// The passed [SPBrightnessGrid] gets consumed.
 | /// The passed [SPBrightnessGrid] gets consumed.
 | ||||||
| ///
 | ///
 | ||||||
| /// Returns: a new [Command::CharBrightness] instance. Will never return NULL.
 | /// Returns: a new [servicepoint::Command::CharBrightness] instance. Will never return NULL.
 | ||||||
| ///
 | ///
 | ||||||
| /// # Panics
 | /// # Panics
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -211,7 +213,7 @@ pub unsafe extern "C" fn sp_command_char_brightness( | ||||||
| ///
 | ///
 | ||||||
| /// The passed [SPBitVec] gets consumed.
 | /// The passed [SPBitVec] gets consumed.
 | ||||||
| ///
 | ///
 | ||||||
| /// Returns: a new [Command::BitmapLinear] instance. Will never return NULL.
 | /// Returns: a new [servicepoint::Command::BitmapLinear] instance. Will never return NULL.
 | ||||||
| ///
 | ///
 | ||||||
| /// # Panics
 | /// # Panics
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -254,7 +256,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear( | ||||||
| ///
 | ///
 | ||||||
| /// The passed [SPBitVec] gets consumed.
 | /// The passed [SPBitVec] gets consumed.
 | ||||||
| ///
 | ///
 | ||||||
| /// Returns: a new [Command::BitmapLinearAnd] instance. Will never return NULL.
 | /// Returns: a new [servicepoint::Command::BitmapLinearAnd] instance. Will never return NULL.
 | ||||||
| ///
 | ///
 | ||||||
| /// # Panics
 | /// # Panics
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -297,7 +299,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_and( | ||||||
| ///
 | ///
 | ||||||
| /// The passed [SPBitVec] gets consumed.
 | /// The passed [SPBitVec] gets consumed.
 | ||||||
| ///
 | ///
 | ||||||
| /// Returns: a new [Command::BitmapLinearOr] instance. Will never return NULL.
 | /// Returns: a new [servicepoint::Command::BitmapLinearOr] instance. Will never return NULL.
 | ||||||
| ///
 | ///
 | ||||||
| /// # Panics
 | /// # Panics
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -340,7 +342,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_or( | ||||||
| ///
 | ///
 | ||||||
| /// The passed [SPBitVec] gets consumed.
 | /// The passed [SPBitVec] gets consumed.
 | ||||||
| ///
 | ///
 | ||||||
| /// Returns: a new [Command::BitmapLinearXor] instance. Will never return NULL.
 | /// Returns: a new [servicepoint::Command::BitmapLinearXor] instance. Will never return NULL.
 | ||||||
| ///
 | ///
 | ||||||
| /// # Panics
 | /// # Panics
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -378,7 +380,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_xor( | ||||||
| ///
 | ///
 | ||||||
| /// The passed [SPCp437Grid] gets consumed.
 | /// The passed [SPCp437Grid] gets consumed.
 | ||||||
| ///
 | ///
 | ||||||
| /// Returns: a new [Command::Cp437Data] instance. Will never return NULL.
 | /// Returns: a new [servicepoint::Command::Cp437Data] instance. Will never return NULL.
 | ||||||
| ///
 | ///
 | ||||||
| /// # Panics
 | /// # Panics
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -410,7 +412,7 @@ pub unsafe extern "C" fn sp_command_cp437_data( | ||||||
| ///
 | ///
 | ||||||
| /// The passed [SPBitmap] gets consumed.
 | /// The passed [SPBitmap] gets consumed.
 | ||||||
| ///
 | ///
 | ||||||
| /// Returns: a new [Command::BitmapLinearWin] instance. Will never return NULL.
 | /// Returns: a new [servicepoint::Command::BitmapLinearWin] instance. Will never return NULL.
 | ||||||
| ///
 | ///
 | ||||||
| /// # Panics
 | /// # Panics
 | ||||||
| ///
 | ///
 | ||||||
|  |  | ||||||
|  | @ -117,6 +117,8 @@ pub unsafe extern "C" fn sp_cp437_grid_clone( | ||||||
| /// - `cp437_grid` points to a valid [SPCp437Grid]
 | /// - `cp437_grid` points to a valid [SPCp437Grid]
 | ||||||
| /// - `cp437_grid` is not used concurrently or after cp437_grid call
 | /// - `cp437_grid` is not used concurrently or after cp437_grid call
 | ||||||
| /// - `cp437_grid` was not passed to another consuming function, e.g. to create a [SPCommand]
 | /// - `cp437_grid` was not passed to another consuming function, e.g. to create a [SPCommand]
 | ||||||
|  | ///
 | ||||||
|  | /// [SPCommand]: [crate::SPCommand]
 | ||||||
| #[no_mangle] | #[no_mangle] | ||||||
| pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) { | pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut SPCp437Grid) { | ||||||
|     assert!(!cp437_grid.is_null()); |     assert!(!cp437_grid.is_null()); | ||||||
|  | @ -172,6 +174,8 @@ pub unsafe extern "C" fn sp_cp437_grid_get( | ||||||
| ///
 | ///
 | ||||||
| /// - `cp437_grid` points to a valid [SPBitVec]
 | /// - `cp437_grid` points to a valid [SPBitVec]
 | ||||||
| /// - `cp437_grid` is not written to or read from concurrently
 | /// - `cp437_grid` is not written to or read from concurrently
 | ||||||
|  | ///
 | ||||||
|  | /// [SPBitVec]: [crate::SPBitVec]
 | ||||||
| #[no_mangle] | #[no_mangle] | ||||||
| pub unsafe extern "C" fn sp_cp437_grid_set( | pub unsafe extern "C" fn sp_cp437_grid_set( | ||||||
|     cp437_grid: *mut SPCp437Grid, |     cp437_grid: *mut SPCp437Grid, | ||||||
|  |  | ||||||
|  | @ -13,8 +13,8 @@ test = false | ||||||
| csbindgen = "1.9.3" | csbindgen = "1.9.3" | ||||||
| 
 | 
 | ||||||
| [dependencies] | [dependencies] | ||||||
| servicepoint_binding_c = { version = "0.10.0", path = "../servicepoint_binding_c" } | servicepoint_binding_c = { version = "0.11.0", path = "../servicepoint_binding_c" } | ||||||
| servicepoint = { version = "0.10.0", path = "../servicepoint" } | servicepoint = { version = "0.11.0", path = "../servicepoint" } | ||||||
| 
 | 
 | ||||||
| [lints] | [lints] | ||||||
| workspace = true | workspace = true | ||||||
|  |  | ||||||
|  | @ -108,6 +108,8 @@ namespace ServicePoint.BindGen | ||||||
|         ///  - `bitmap` points to a valid [SPBitmap] |         ///  - `bitmap` points to a valid [SPBitmap] | ||||||
|         ///  - `bitmap` is not used concurrently or after bitmap call |         ///  - `bitmap` is not used concurrently or after bitmap call | ||||||
|         ///  - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] |         ///  - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand] | ||||||
|  |         /// | ||||||
|  |         ///  [SPCommand]: [crate::SPCommand] | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         [DllImport(__DllName, EntryPoint = "sp_bitmap_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] |         [DllImport(__DllName, EntryPoint = "sp_bitmap_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||||
|         public static extern void sp_bitmap_free(Bitmap* bitmap); |         public static extern void sp_bitmap_free(Bitmap* bitmap); | ||||||
|  | @ -321,6 +323,8 @@ namespace ServicePoint.BindGen | ||||||
|         ///  - `bit_vec` points to a valid [SPBitVec] |         ///  - `bit_vec` points to a valid [SPBitVec] | ||||||
|         ///  - `bit_vec` is not used concurrently or after this call |         ///  - `bit_vec` is not used concurrently or after this call | ||||||
|         ///  - `bit_vec` was not passed to another consuming function, e.g. to create a [SPCommand] |         ///  - `bit_vec` was not passed to another consuming function, e.g. to create a [SPCommand] | ||||||
|  |         /// | ||||||
|  |         ///  [SPCommand]: [crate::SPCommand] | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         [DllImport(__DllName, EntryPoint = "sp_bitvec_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] |         [DllImport(__DllName, EntryPoint = "sp_bitvec_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||||
|         public static extern void sp_bitvec_free(BitVec* bit_vec); |         public static extern void sp_bitvec_free(BitVec* bit_vec); | ||||||
|  | @ -540,6 +544,8 @@ namespace ServicePoint.BindGen | ||||||
|         ///  - `brightness_grid` points to a valid [SPBrightnessGrid] |         ///  - `brightness_grid` points to a valid [SPBrightnessGrid] | ||||||
|         ///  - `brightness_grid` is not used concurrently or after this call |         ///  - `brightness_grid` is not used concurrently or after this call | ||||||
|         ///  - `brightness_grid` was not passed to another consuming function, e.g. to create a [SPCommand] |         ///  - `brightness_grid` was not passed to another consuming function, e.g. to create a [SPCommand] | ||||||
|  |         /// | ||||||
|  |         ///  [SPCommand]: [crate::SPCommand] | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         [DllImport(__DllName, EntryPoint = "sp_brightness_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] |         [DllImport(__DllName, EntryPoint = "sp_brightness_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||||
|         public static extern void sp_brightness_grid_free(BrightnessGrid* brightness_grid); |         public static extern void sp_brightness_grid_free(BrightnessGrid* brightness_grid); | ||||||
|  | @ -590,7 +596,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// |         /// | ||||||
|         ///  The caller has to make sure that: |         ///  The caller has to make sure that: | ||||||
|         /// |         /// | ||||||
|         ///  - `brightness_grid` points to a valid [SPBitVec] |         ///  - `brightness_grid` points to a valid [SPBrightnessGrid] | ||||||
|         ///  - `brightness_grid` is not written to or read from concurrently |         ///  - `brightness_grid` is not written to or read from concurrently | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         [DllImport(__DllName, EntryPoint = "sp_brightness_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] |         [DllImport(__DllName, EntryPoint = "sp_brightness_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||||
|  | @ -737,7 +743,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// |         /// | ||||||
|         ///  Does not affect brightness. |         ///  Does not affect brightness. | ||||||
|         /// |         /// | ||||||
|         ///  Returns: a new [Command::Clear] instance. Will never return NULL. |         ///  Returns: a new [servicepoint::Command::Clear] instance. Will never return NULL. | ||||||
|         /// |         /// | ||||||
|         ///  # Examples |         ///  # Examples | ||||||
|         /// |         /// | ||||||
|  | @ -760,7 +766,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// |         /// | ||||||
|         ///  Please do not send this in your normal program flow. |         ///  Please do not send this in your normal program flow. | ||||||
|         /// |         /// | ||||||
|         ///  Returns: a new [Command::HardReset] instance. Will never return NULL. |         ///  Returns: a new [servicepoint::Command::HardReset] instance. Will never return NULL. | ||||||
|         /// |         /// | ||||||
|         ///  # Safety |         ///  # Safety | ||||||
|         /// |         /// | ||||||
|  | @ -775,7 +781,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///  A yet-to-be-tested command. |         ///  A yet-to-be-tested command. | ||||||
|         /// |         /// | ||||||
|         ///  Returns: a new `Command::FadeOut` instance. Will never return NULL. |         ///  Returns: a new [servicepoint::Command::FadeOut] instance. Will never return NULL. | ||||||
|         /// |         /// | ||||||
|         ///  # Safety |         ///  # Safety | ||||||
|         /// |         /// | ||||||
|  | @ -790,7 +796,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///  Set the brightness of all tiles to the same value. |         ///  Set the brightness of all tiles to the same value. | ||||||
|         /// |         /// | ||||||
|         ///  Returns: a new [Command::Brightness] instance. Will never return NULL. |         ///  Returns: a new [servicepoint::Command::Brightness] instance. Will never return NULL. | ||||||
|         /// |         /// | ||||||
|         ///  # Panics |         ///  # Panics | ||||||
|         /// |         /// | ||||||
|  | @ -811,7 +817,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// |         /// | ||||||
|         ///  The passed [SPBrightnessGrid] gets consumed. |         ///  The passed [SPBrightnessGrid] gets consumed. | ||||||
|         /// |         /// | ||||||
|         ///  Returns: a new [Command::CharBrightness] instance. Will never return NULL. |         ///  Returns: a new [servicepoint::Command::CharBrightness] instance. Will never return NULL. | ||||||
|         /// |         /// | ||||||
|         ///  # Panics |         ///  # Panics | ||||||
|         /// |         /// | ||||||
|  | @ -839,7 +845,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// |         /// | ||||||
|         ///  The passed [SPBitVec] gets consumed. |         ///  The passed [SPBitVec] gets consumed. | ||||||
|         /// |         /// | ||||||
|         ///  Returns: a new [Command::BitmapLinear] instance. Will never return NULL. |         ///  Returns: a new [servicepoint::Command::BitmapLinear] instance. Will never return NULL. | ||||||
|         /// |         /// | ||||||
|         ///  # Panics |         ///  # Panics | ||||||
|         /// |         /// | ||||||
|  | @ -869,7 +875,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// |         /// | ||||||
|         ///  The passed [SPBitVec] gets consumed. |         ///  The passed [SPBitVec] gets consumed. | ||||||
|         /// |         /// | ||||||
|         ///  Returns: a new [Command::BitmapLinearAnd] instance. Will never return NULL. |         ///  Returns: a new [servicepoint::Command::BitmapLinearAnd] instance. Will never return NULL. | ||||||
|         /// |         /// | ||||||
|         ///  # Panics |         ///  # Panics | ||||||
|         /// |         /// | ||||||
|  | @ -899,7 +905,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// |         /// | ||||||
|         ///  The passed [SPBitVec] gets consumed. |         ///  The passed [SPBitVec] gets consumed. | ||||||
|         /// |         /// | ||||||
|         ///  Returns: a new [Command::BitmapLinearOr] instance. Will never return NULL. |         ///  Returns: a new [servicepoint::Command::BitmapLinearOr] instance. Will never return NULL. | ||||||
|         /// |         /// | ||||||
|         ///  # Panics |         ///  # Panics | ||||||
|         /// |         /// | ||||||
|  | @ -929,7 +935,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// |         /// | ||||||
|         ///  The passed [SPBitVec] gets consumed. |         ///  The passed [SPBitVec] gets consumed. | ||||||
|         /// |         /// | ||||||
|         ///  Returns: a new [Command::BitmapLinearXor] instance. Will never return NULL. |         ///  Returns: a new [servicepoint::Command::BitmapLinearXor] instance. Will never return NULL. | ||||||
|         /// |         /// | ||||||
|         ///  # Panics |         ///  # Panics | ||||||
|         /// |         /// | ||||||
|  | @ -954,7 +960,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// |         /// | ||||||
|         ///  The passed [SPCp437Grid] gets consumed. |         ///  The passed [SPCp437Grid] gets consumed. | ||||||
|         /// |         /// | ||||||
|         ///  Returns: a new [Command::Cp437Data] instance. Will never return NULL. |         ///  Returns: a new [servicepoint::Command::Cp437Data] instance. Will never return NULL. | ||||||
|         /// |         /// | ||||||
|         ///  # Panics |         ///  # Panics | ||||||
|         /// |         /// | ||||||
|  | @ -977,7 +983,7 @@ namespace ServicePoint.BindGen | ||||||
|         /// |         /// | ||||||
|         ///  The passed [SPBitmap] gets consumed. |         ///  The passed [SPBitmap] gets consumed. | ||||||
|         /// |         /// | ||||||
|         ///  Returns: a new [Command::BitmapLinearWin] instance. Will never return NULL. |         ///  Returns: a new [servicepoint::Command::BitmapLinearWin] instance. Will never return NULL. | ||||||
|         /// |         /// | ||||||
|         ///  # Panics |         ///  # Panics | ||||||
|         /// |         /// | ||||||
|  | @ -1178,6 +1184,8 @@ namespace ServicePoint.BindGen | ||||||
|         ///  - `cp437_grid` points to a valid [SPCp437Grid] |         ///  - `cp437_grid` points to a valid [SPCp437Grid] | ||||||
|         ///  - `cp437_grid` is not used concurrently or after cp437_grid call |         ///  - `cp437_grid` is not used concurrently or after cp437_grid call | ||||||
|         ///  - `cp437_grid` was not passed to another consuming function, e.g. to create a [SPCommand] |         ///  - `cp437_grid` was not passed to another consuming function, e.g. to create a [SPCommand] | ||||||
|  |         /// | ||||||
|  |         ///  [SPCommand]: [crate::SPCommand] | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         [DllImport(__DllName, EntryPoint = "sp_cp437_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] |         [DllImport(__DllName, EntryPoint = "sp_cp437_grid_free", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||||
|         public static extern void sp_cp437_grid_free(Cp437Grid* cp437_grid); |         public static extern void sp_cp437_grid_free(Cp437Grid* cp437_grid); | ||||||
|  | @ -1227,6 +1235,8 @@ namespace ServicePoint.BindGen | ||||||
|         /// |         /// | ||||||
|         ///  - `cp437_grid` points to a valid [SPBitVec] |         ///  - `cp437_grid` points to a valid [SPBitVec] | ||||||
|         ///  - `cp437_grid` is not written to or read from concurrently |         ///  - `cp437_grid` is not written to or read from concurrently | ||||||
|  |         /// | ||||||
|  |         ///  [SPBitVec]: [crate::SPBitVec] | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         [DllImport(__DllName, EntryPoint = "sp_cp437_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] |         [DllImport(__DllName, EntryPoint = "sp_cp437_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||||
|         public static extern void sp_cp437_grid_set(Cp437Grid* cp437_grid, nuint x, nuint y, byte value); |         public static extern void sp_cp437_grid_set(Cp437Grid* cp437_grid, nuint x, nuint y, byte value); | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ | ||||||
| 
 | 
 | ||||||
|     <PropertyGroup> |     <PropertyGroup> | ||||||
|         <PackageId>ServicePoint</PackageId> |         <PackageId>ServicePoint</PackageId> | ||||||
|         <Version>0.10.0</Version> |         <Version>0.11.0</Version> | ||||||
|         <Authors>Repository Authors</Authors> |         <Authors>Repository Authors</Authors> | ||||||
|         <Company>None</Company> |         <Company>None</Company> | ||||||
|         <Product>ServicePoint</Product> |         <Product>ServicePoint</Product> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vinzenz Schroeter
						Vinzenz Schroeter