feat: create initial version of proc_macro and lib
This commit is contained in:
		
							parent
							
								
									7dc755dde4
								
							
						
					
					
						commit
						c459800fca
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1 +1 @@
 | 
				
			|||||||
/target
 | 
					/target
 | 
				
			||||||
@ -21,6 +21,7 @@ rust:clippy:
 | 
				
			|||||||
  stage: test
 | 
					  stage: test
 | 
				
			||||||
  image: rust:1.84-alpine3.21
 | 
					  image: rust:1.84-alpine3.21
 | 
				
			||||||
  before_script:
 | 
					  before_script:
 | 
				
			||||||
 | 
					    - apk add musl-dev
 | 
				
			||||||
    - rustup component add clippy
 | 
					    - rustup component add clippy
 | 
				
			||||||
  script:
 | 
					  script:
 | 
				
			||||||
    - cargo clippy --all-features -- -D warnings
 | 
					    - cargo clippy --all-features -- -D warnings
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										610
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										610
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -2,6 +2,616 @@
 | 
				
			|||||||
# It is not intended for manual editing.
 | 
					# It is not intended for manual editing.
 | 
				
			||||||
version = 4
 | 
					version = 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "addr2line"
 | 
				
			||||||
 | 
					version = "0.24.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "gimli",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "adler2"
 | 
				
			||||||
 | 
					version = "2.0.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "axum"
 | 
				
			||||||
 | 
					version = "0.8.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "axum-core",
 | 
				
			||||||
 | 
					 "bytes",
 | 
				
			||||||
 | 
					 "futures-util",
 | 
				
			||||||
 | 
					 "http",
 | 
				
			||||||
 | 
					 "http-body",
 | 
				
			||||||
 | 
					 "http-body-util",
 | 
				
			||||||
 | 
					 "itoa",
 | 
				
			||||||
 | 
					 "matchit",
 | 
				
			||||||
 | 
					 "memchr",
 | 
				
			||||||
 | 
					 "mime",
 | 
				
			||||||
 | 
					 "percent-encoding",
 | 
				
			||||||
 | 
					 "pin-project-lite",
 | 
				
			||||||
 | 
					 "rustversion",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 | 
					 "sync_wrapper",
 | 
				
			||||||
 | 
					 "tower",
 | 
				
			||||||
 | 
					 "tower-layer",
 | 
				
			||||||
 | 
					 "tower-service",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "axum-core"
 | 
				
			||||||
 | 
					version = "0.5.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "bytes",
 | 
				
			||||||
 | 
					 "futures-util",
 | 
				
			||||||
 | 
					 "http",
 | 
				
			||||||
 | 
					 "http-body",
 | 
				
			||||||
 | 
					 "http-body-util",
 | 
				
			||||||
 | 
					 "mime",
 | 
				
			||||||
 | 
					 "pin-project-lite",
 | 
				
			||||||
 | 
					 "rustversion",
 | 
				
			||||||
 | 
					 "sync_wrapper",
 | 
				
			||||||
 | 
					 "tower-layer",
 | 
				
			||||||
 | 
					 "tower-service",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "backtrace"
 | 
				
			||||||
 | 
					version = "0.3.74"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "addr2line",
 | 
				
			||||||
 | 
					 "cfg-if",
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					 "miniz_oxide",
 | 
				
			||||||
 | 
					 "object",
 | 
				
			||||||
 | 
					 "rustc-demangle",
 | 
				
			||||||
 | 
					 "windows-targets",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "block-buffer"
 | 
				
			||||||
 | 
					version = "0.10.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "generic-array",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "bytes"
 | 
				
			||||||
 | 
					version = "1.10.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "cc"
 | 
				
			||||||
 | 
					version = "1.2.16"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "jobserver",
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					 "shlex",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "cfg-if"
 | 
				
			||||||
 | 
					version = "1.0.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "cpufeatures"
 | 
				
			||||||
 | 
					version = "0.2.17"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "crc32fast"
 | 
				
			||||||
 | 
					version = "1.4.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "cfg-if",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "crypto-common"
 | 
				
			||||||
 | 
					version = "0.1.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "generic-array",
 | 
				
			||||||
 | 
					 "typenum",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "digest"
 | 
				
			||||||
 | 
					version = "0.10.7"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "block-buffer",
 | 
				
			||||||
 | 
					 "crypto-common",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "display_full_error"
 | 
				
			||||||
 | 
					version = "1.1.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "bc7c47e9a2fd28a8edd1446f10dabe8ac5d26bb77ed2b1077bfcd8308904e8c6"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "flate2"
 | 
				
			||||||
 | 
					version = "1.1.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "crc32fast",
 | 
				
			||||||
 | 
					 "miniz_oxide",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "fnv"
 | 
				
			||||||
 | 
					version = "1.0.7"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "futures-core"
 | 
				
			||||||
 | 
					version = "0.3.31"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "futures-task"
 | 
				
			||||||
 | 
					version = "0.3.31"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "futures-util"
 | 
				
			||||||
 | 
					version = "0.3.31"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "futures-core",
 | 
				
			||||||
 | 
					 "futures-task",
 | 
				
			||||||
 | 
					 "pin-project-lite",
 | 
				
			||||||
 | 
					 "pin-utils",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "generic-array"
 | 
				
			||||||
 | 
					version = "0.14.7"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "typenum",
 | 
				
			||||||
 | 
					 "version_check",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "gimli"
 | 
				
			||||||
 | 
					version = "0.31.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "glob"
 | 
				
			||||||
 | 
					version = "0.3.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "http"
 | 
				
			||||||
 | 
					version = "1.3.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "bytes",
 | 
				
			||||||
 | 
					 "fnv",
 | 
				
			||||||
 | 
					 "itoa",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "http-body"
 | 
				
			||||||
 | 
					version = "1.0.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "bytes",
 | 
				
			||||||
 | 
					 "http",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "http-body-util"
 | 
				
			||||||
 | 
					version = "0.1.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "bytes",
 | 
				
			||||||
 | 
					 "futures-core",
 | 
				
			||||||
 | 
					 "http",
 | 
				
			||||||
 | 
					 "http-body",
 | 
				
			||||||
 | 
					 "pin-project-lite",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "itoa"
 | 
				
			||||||
 | 
					version = "1.0.15"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "jobserver"
 | 
				
			||||||
 | 
					version = "0.1.32"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "libc"
 | 
				
			||||||
 | 
					version = "0.2.171"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "matchit"
 | 
				
			||||||
 | 
					version = "0.8.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "memchr"
 | 
				
			||||||
 | 
					version = "2.7.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "mime"
 | 
				
			||||||
 | 
					version = "0.3.17"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "miniz_oxide"
 | 
				
			||||||
 | 
					version = "0.8.5"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "adler2",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "object"
 | 
				
			||||||
 | 
					version = "0.36.7"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "memchr",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "percent-encoding"
 | 
				
			||||||
 | 
					version = "2.3.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "pin-project-lite"
 | 
				
			||||||
 | 
					version = "0.2.16"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "pin-utils"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "pkg-config"
 | 
				
			||||||
 | 
					version = "0.3.32"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "proc-macro2"
 | 
				
			||||||
 | 
					version = "1.0.94"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "unicode-ident",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "quote"
 | 
				
			||||||
 | 
					version = "1.0.40"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rustc-demangle"
 | 
				
			||||||
 | 
					version = "0.1.24"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rustversion"
 | 
				
			||||||
 | 
					version = "1.0.20"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "serde"
 | 
				
			||||||
 | 
					version = "1.0.219"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "serde_derive",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "serde_derive"
 | 
				
			||||||
 | 
					version = "1.0.219"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "sha1"
 | 
				
			||||||
 | 
					version = "0.10.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "cfg-if",
 | 
				
			||||||
 | 
					 "cpufeatures",
 | 
				
			||||||
 | 
					 "digest",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "shlex"
 | 
				
			||||||
 | 
					version = "1.3.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "static-serve"
 | 
					name = "static-serve"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "axum",
 | 
				
			||||||
 | 
					 "bytes",
 | 
				
			||||||
 | 
					 "static-serve-macro",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "static-serve-macro"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "display_full_error",
 | 
				
			||||||
 | 
					 "flate2",
 | 
				
			||||||
 | 
					 "glob",
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "sha1",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					 "thiserror",
 | 
				
			||||||
 | 
					 "zstd",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "syn"
 | 
				
			||||||
 | 
					version = "2.0.100"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "unicode-ident",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "sync_wrapper"
 | 
				
			||||||
 | 
					version = "1.0.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "thiserror"
 | 
				
			||||||
 | 
					version = "2.0.12"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "thiserror-impl",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "thiserror-impl"
 | 
				
			||||||
 | 
					version = "2.0.12"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "tokio"
 | 
				
			||||||
 | 
					version = "1.44.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "backtrace",
 | 
				
			||||||
 | 
					 "pin-project-lite",
 | 
				
			||||||
 | 
					 "tokio-macros",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "tokio-macros"
 | 
				
			||||||
 | 
					version = "2.5.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "tower"
 | 
				
			||||||
 | 
					version = "0.5.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "futures-core",
 | 
				
			||||||
 | 
					 "futures-util",
 | 
				
			||||||
 | 
					 "pin-project-lite",
 | 
				
			||||||
 | 
					 "sync_wrapper",
 | 
				
			||||||
 | 
					 "tower-layer",
 | 
				
			||||||
 | 
					 "tower-service",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "tower-layer"
 | 
				
			||||||
 | 
					version = "0.3.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "tower-service"
 | 
				
			||||||
 | 
					version = "0.3.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "typenum"
 | 
				
			||||||
 | 
					version = "1.18.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "unicode-ident"
 | 
				
			||||||
 | 
					version = "1.0.18"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "version_check"
 | 
				
			||||||
 | 
					version = "0.9.5"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows-targets"
 | 
				
			||||||
 | 
					version = "0.52.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "windows_aarch64_gnullvm",
 | 
				
			||||||
 | 
					 "windows_aarch64_msvc",
 | 
				
			||||||
 | 
					 "windows_i686_gnu",
 | 
				
			||||||
 | 
					 "windows_i686_gnullvm",
 | 
				
			||||||
 | 
					 "windows_i686_msvc",
 | 
				
			||||||
 | 
					 "windows_x86_64_gnu",
 | 
				
			||||||
 | 
					 "windows_x86_64_gnullvm",
 | 
				
			||||||
 | 
					 "windows_x86_64_msvc",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_aarch64_gnullvm"
 | 
				
			||||||
 | 
					version = "0.52.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_aarch64_msvc"
 | 
				
			||||||
 | 
					version = "0.52.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_i686_gnu"
 | 
				
			||||||
 | 
					version = "0.52.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_i686_gnullvm"
 | 
				
			||||||
 | 
					version = "0.52.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_i686_msvc"
 | 
				
			||||||
 | 
					version = "0.52.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_x86_64_gnu"
 | 
				
			||||||
 | 
					version = "0.52.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_x86_64_gnullvm"
 | 
				
			||||||
 | 
					version = "0.52.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_x86_64_msvc"
 | 
				
			||||||
 | 
					version = "0.52.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "zstd"
 | 
				
			||||||
 | 
					version = "0.13.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "zstd-safe",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "zstd-safe"
 | 
				
			||||||
 | 
					version = "7.2.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "zstd-sys",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "zstd-sys"
 | 
				
			||||||
 | 
					version = "2.0.15+zstd.1.5.7"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "cc",
 | 
				
			||||||
 | 
					 "pkg-config",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										24
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								Cargo.toml
									
									
									
									
									
								
							@ -1,16 +1,26 @@
 | 
				
			|||||||
[package]
 | 
					[workspace]
 | 
				
			||||||
name = "static-serve"
 | 
					members = [
 | 
				
			||||||
 | 
					    "static-serve",
 | 
				
			||||||
 | 
					    "static-serve-macro",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					resolver = "2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[workspace.package]
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
edition = "2021"
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					rust-version = "1.83"
 | 
				
			||||||
 | 
					description = "A helper for compressing and embedding static assets in an Axum webserver"
 | 
				
			||||||
 | 
					repository = "https://github.com/M4SS-Code/static-serve"
 | 
				
			||||||
license = "MIT OR Apache-2.0"
 | 
					license = "MIT OR Apache-2.0"
 | 
				
			||||||
 | 
					keywords = ["static", "axum", "embed", "web", "conditional"]
 | 
				
			||||||
 | 
					categories = ["web-programming", "web-programming::http-server", "filesystem"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[workspace.lints.rust]
 | 
				
			||||||
 | 
					missing_docs = "warn"
 | 
				
			||||||
[lints.rust]
 | 
					 | 
				
			||||||
unsafe_code = "deny"
 | 
					unsafe_code = "deny"
 | 
				
			||||||
unreachable_pub = "deny"
 | 
					unreachable_pub = "deny"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[lints.clippy]
 | 
					[workspace.lints.clippy]
 | 
				
			||||||
pedantic = { level = "warn", priority = -1 }
 | 
					pedantic = { level = "warn", priority = -1 }
 | 
				
			||||||
module_name_repetitions = "allow"
 | 
					module_name_repetitions = "allow"
 | 
				
			||||||
await_holding_refcell_ref = "deny"
 | 
					await_holding_refcell_ref = "deny"
 | 
				
			||||||
@ -20,4 +30,4 @@ needless_raw_string_hashes = "warn"
 | 
				
			|||||||
redundant_closure_for_method_calls = "warn"
 | 
					redundant_closure_for_method_calls = "warn"
 | 
				
			||||||
semicolon_if_nothing_returned = "warn"
 | 
					semicolon_if_nothing_returned = "warn"
 | 
				
			||||||
str_to_string = "warn"
 | 
					str_to_string = "warn"
 | 
				
			||||||
clone_on_ref_ptr = "warn"
 | 
					clone_on_ref_ptr = "warn"
 | 
				
			||||||
@ -6,6 +6,8 @@ ignore = [
 | 
				
			|||||||
allow = [
 | 
					allow = [
 | 
				
			||||||
    "MIT",
 | 
					    "MIT",
 | 
				
			||||||
    "Apache-2.0",
 | 
					    "Apache-2.0",
 | 
				
			||||||
 | 
					    "Unicode-3.0",
 | 
				
			||||||
 | 
					    "BSD-3-Clause",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[licenses.private]
 | 
					[licenses.private]
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +0,0 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
							
								
								
									
										27
									
								
								static-serve-macro/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								static-serve-macro/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "static-serve-macro"
 | 
				
			||||||
 | 
					version.workspace = true
 | 
				
			||||||
 | 
					edition.workspace = true
 | 
				
			||||||
 | 
					license.workspace = true
 | 
				
			||||||
 | 
					rust-version.workspace = true
 | 
				
			||||||
 | 
					keywords.workspace = true
 | 
				
			||||||
 | 
					description.workspace = true
 | 
				
			||||||
 | 
					categories.workspace = true
 | 
				
			||||||
 | 
					repository.workspace = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[lib]
 | 
				
			||||||
 | 
					proc-macro = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					display_full_error = "1.1"
 | 
				
			||||||
 | 
					flate2 = "1.1"
 | 
				
			||||||
 | 
					glob = "0.3"
 | 
				
			||||||
 | 
					proc-macro2 = "1.0"
 | 
				
			||||||
 | 
					quote = "1.0"
 | 
				
			||||||
 | 
					sha1 = "0.10"
 | 
				
			||||||
 | 
					syn = { version = "2.0", default-features = false }
 | 
				
			||||||
 | 
					thiserror = "2.0.12"
 | 
				
			||||||
 | 
					zstd = "0.13"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[lints]
 | 
				
			||||||
 | 
					workspace = true
 | 
				
			||||||
							
								
								
									
										82
									
								
								static-serve-macro/src/error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								static-serve-macro/src/error.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					use std::{
 | 
				
			||||||
 | 
					    ffi::{OsStr, OsString},
 | 
				
			||||||
 | 
					    fmt::{Display, Formatter},
 | 
				
			||||||
 | 
					    io,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use glob::{GlobError, PatternError};
 | 
				
			||||||
 | 
					use thiserror::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					pub(crate) enum Error {
 | 
				
			||||||
 | 
					    #[error("{}", UnknownFileExtension(.0.as_deref()))]
 | 
				
			||||||
 | 
					    UnknownFileExtension(Option<OsString>),
 | 
				
			||||||
 | 
					    #[error("Cannot canonicalize assets directory")]
 | 
				
			||||||
 | 
					    CannotCanonicalizeDirectory(#[source] io::Error),
 | 
				
			||||||
 | 
					    #[error("Invalid unicode in directory name")]
 | 
				
			||||||
 | 
					    InvalidUnicodeInDirectoryName,
 | 
				
			||||||
 | 
					    #[error("Cannot canonicalize ignore directory")]
 | 
				
			||||||
 | 
					    CannotCanonicalizeIgnoreDir(#[source] io::Error),
 | 
				
			||||||
 | 
					    #[error("Invalid unicode in directory name")]
 | 
				
			||||||
 | 
					    InvalidUnicodeInEntryName,
 | 
				
			||||||
 | 
					    #[error("Error while compressing with gzip")]
 | 
				
			||||||
 | 
					    Gzip(#[from] GzipType),
 | 
				
			||||||
 | 
					    #[error("Error while compressing with zstd")]
 | 
				
			||||||
 | 
					    Zstd(#[from] ZstdType),
 | 
				
			||||||
 | 
					    #[error("Error while reading entry contents")]
 | 
				
			||||||
 | 
					    CannotReadEntryContents(#[source] io::Error),
 | 
				
			||||||
 | 
					    #[error("Error while parsing glob pattern")]
 | 
				
			||||||
 | 
					    Pattern(#[source] PatternError),
 | 
				
			||||||
 | 
					    #[error("Error reading path for glob")]
 | 
				
			||||||
 | 
					    Glob(#[source] GlobError),
 | 
				
			||||||
 | 
					    #[error("Cannot get entry metadata")]
 | 
				
			||||||
 | 
					    CannotGetMetadata(#[source] io::Error),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct UnknownFileExtension<'a>(Option<&'a OsStr>);
 | 
				
			||||||
 | 
					impl Display for UnknownFileExtension<'_> {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        match self.0 {
 | 
				
			||||||
 | 
					            Some(ext) => write!(
 | 
				
			||||||
 | 
					                f,
 | 
				
			||||||
 | 
					                "Unknown file extension in directory of static assets: {}",
 | 
				
			||||||
 | 
					                ext.to_string_lossy()
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            None => write!(f, "Missing file extension"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					pub(crate) enum GzipType {
 | 
				
			||||||
 | 
					    #[error("The compressor could not write")]
 | 
				
			||||||
 | 
					    CompressorWrite(#[source] io::Error),
 | 
				
			||||||
 | 
					    #[error("The encoder could not complete the `finish` procedure")]
 | 
				
			||||||
 | 
					    EncoderFinish(#[source] io::Error),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					pub(crate) enum ZstdType {
 | 
				
			||||||
 | 
					    #[error("The encoder could not write")]
 | 
				
			||||||
 | 
					    EncoderWrite(#[source] io::Error),
 | 
				
			||||||
 | 
					    #[error("The encoder could not complete the `finish` procedure")]
 | 
				
			||||||
 | 
					    EncoderFinish(#[source] io::Error),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod test {
 | 
				
			||||||
 | 
					    use std::ffi::OsStr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use super::UnknownFileExtension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn unknown_file_extension() {
 | 
				
			||||||
 | 
					        let missing_extension = UnknownFileExtension(None);
 | 
				
			||||||
 | 
					        assert_eq!(missing_extension.to_string(), "Missing file extension");
 | 
				
			||||||
 | 
					        let unknown_extension = UnknownFileExtension(Some(OsStr::new("pippo")));
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            unknown_extension.to_string(),
 | 
				
			||||||
 | 
					            "Unknown file extension in directory of static assets: pippo"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										407
									
								
								static-serve-macro/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										407
									
								
								static-serve-macro/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,407 @@
 | 
				
			|||||||
 | 
					//! Proc macro crate for compressing and embedding static assets
 | 
				
			||||||
 | 
					//! in a web server
 | 
				
			||||||
 | 
					//! Macro invocation: `embed_assets!('path/to/assets', compress = true);`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::{
 | 
				
			||||||
 | 
					    convert::Into,
 | 
				
			||||||
 | 
					    fmt::Display,
 | 
				
			||||||
 | 
					    fs,
 | 
				
			||||||
 | 
					    io::{self, Write},
 | 
				
			||||||
 | 
					    path::{Path, PathBuf},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use display_full_error::DisplayFullError;
 | 
				
			||||||
 | 
					use flate2::write::GzEncoder;
 | 
				
			||||||
 | 
					use glob::glob;
 | 
				
			||||||
 | 
					use proc_macro2::{Span, TokenStream};
 | 
				
			||||||
 | 
					use quote::{quote, ToTokens};
 | 
				
			||||||
 | 
					use sha1::{Digest as _, Sha1};
 | 
				
			||||||
 | 
					use syn::{
 | 
				
			||||||
 | 
					    bracketed,
 | 
				
			||||||
 | 
					    parse::{Parse, ParseStream},
 | 
				
			||||||
 | 
					    parse_macro_input, Ident, LitBool, LitByteStr, LitStr, Token,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod error;
 | 
				
			||||||
 | 
					use error::{Error, GzipType, ZstdType};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[proc_macro]
 | 
				
			||||||
 | 
					/// Embed and optionally compress static assets for a web server
 | 
				
			||||||
 | 
					pub fn embed_assets(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
 | 
				
			||||||
 | 
					    let parsed = parse_macro_input!(input as EmbedAssets);
 | 
				
			||||||
 | 
					    quote! { #parsed }.into()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct EmbedAssets {
 | 
				
			||||||
 | 
					    assets_dir: AssetsDir,
 | 
				
			||||||
 | 
					    validated_ignore_dirs: IgnoreDirs,
 | 
				
			||||||
 | 
					    should_compress: ShouldCompress,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Parse for EmbedAssets {
 | 
				
			||||||
 | 
					    fn parse(input: ParseStream) -> syn::Result<Self> {
 | 
				
			||||||
 | 
					        let assets_dir: AssetsDir = input.parse()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Default to no compression
 | 
				
			||||||
 | 
					        let mut maybe_should_compress = None;
 | 
				
			||||||
 | 
					        let mut maybe_ignore_dirs = None;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while !input.is_empty() {
 | 
				
			||||||
 | 
					            input.parse::<Token![,]>()?;
 | 
				
			||||||
 | 
					            let key: Ident = input.parse()?;
 | 
				
			||||||
 | 
					            input.parse::<Token![=]>()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            match key.to_string().as_str() {
 | 
				
			||||||
 | 
					                "compress" => {
 | 
				
			||||||
 | 
					                    let value = input.parse()?;
 | 
				
			||||||
 | 
					                    maybe_should_compress = Some(value);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                "ignore_dirs" => {
 | 
				
			||||||
 | 
					                    let value = input.parse()?;
 | 
				
			||||||
 | 
					                    maybe_ignore_dirs = Some(value);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                _ => {
 | 
				
			||||||
 | 
					                    return Err(syn::Error::new(
 | 
				
			||||||
 | 
					                        key.span(),
 | 
				
			||||||
 | 
					                        "Unknown key in embed_assets! macro. Expected `compress` or `ignore_dirs`",
 | 
				
			||||||
 | 
					                    ));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let should_compress = maybe_should_compress.unwrap_or_else(|| {
 | 
				
			||||||
 | 
					            ShouldCompress(LitBool {
 | 
				
			||||||
 | 
					                value: false,
 | 
				
			||||||
 | 
					                span: Span::call_site(),
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let ignore_dirs_with_span = maybe_ignore_dirs.unwrap_or(IgnoreDirsWithSpan(vec![]));
 | 
				
			||||||
 | 
					        let validated_ignore_dirs = validate_ignore_dirs(ignore_dirs_with_span, &assets_dir.0)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            assets_dir,
 | 
				
			||||||
 | 
					            validated_ignore_dirs,
 | 
				
			||||||
 | 
					            should_compress,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ToTokens for EmbedAssets {
 | 
				
			||||||
 | 
					    fn to_tokens(&self, tokens: &mut TokenStream) {
 | 
				
			||||||
 | 
					        let AssetsDir(assets_dir) = &self.assets_dir;
 | 
				
			||||||
 | 
					        let ignore_dirs = &self.validated_ignore_dirs;
 | 
				
			||||||
 | 
					        let ShouldCompress(should_compress) = &self.should_compress;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let result = generate_static_routes(assets_dir, ignore_dirs, should_compress);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        match result {
 | 
				
			||||||
 | 
					            Ok(value) => {
 | 
				
			||||||
 | 
					                tokens.extend(quote! {
 | 
				
			||||||
 | 
					                    #value
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Err(err_message) => {
 | 
				
			||||||
 | 
					                let error = syn::Error::new(Span::call_site(), err_message);
 | 
				
			||||||
 | 
					                tokens.extend(error.to_compile_error());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct AssetsDir(ValidAssetsDirTypes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Parse for AssetsDir {
 | 
				
			||||||
 | 
					    fn parse(input: ParseStream) -> syn::Result<Self> {
 | 
				
			||||||
 | 
					        let input_span = input.span();
 | 
				
			||||||
 | 
					        let assets_dir: ValidAssetsDirTypes = input.parse()?;
 | 
				
			||||||
 | 
					        let literal = assets_dir.to_string();
 | 
				
			||||||
 | 
					        let path = Path::new(&literal);
 | 
				
			||||||
 | 
					        let metadata = match fs::metadata(path) {
 | 
				
			||||||
 | 
					            Ok(meta) => meta,
 | 
				
			||||||
 | 
					            Err(e) if matches!(e.kind(), std::io::ErrorKind::NotFound) => {
 | 
				
			||||||
 | 
					                return Err(syn::Error::new(
 | 
				
			||||||
 | 
					                    input_span,
 | 
				
			||||||
 | 
					                    "The specified assets directory does not exist",
 | 
				
			||||||
 | 
					                ));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Err(e) => {
 | 
				
			||||||
 | 
					                return Err(syn::Error::new(
 | 
				
			||||||
 | 
					                    input_span,
 | 
				
			||||||
 | 
					                    format!(
 | 
				
			||||||
 | 
					                        "Error reading directory {literal}: {}",
 | 
				
			||||||
 | 
					                        DisplayFullError(&e)
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                ));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if !metadata.is_dir() {
 | 
				
			||||||
 | 
					            return Err(syn::Error::new(
 | 
				
			||||||
 | 
					                input_span,
 | 
				
			||||||
 | 
					                "The specified assets directory is not a directory",
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(AssetsDir(assets_dir))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum ValidAssetsDirTypes {
 | 
				
			||||||
 | 
					    LiteralStr(LitStr),
 | 
				
			||||||
 | 
					    Ident(Ident),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for ValidAssetsDirTypes {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::LiteralStr(inner) => write!(f, "{}", inner.value()),
 | 
				
			||||||
 | 
					            Self::Ident(inner) => write!(f, "{inner}"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Parse for ValidAssetsDirTypes {
 | 
				
			||||||
 | 
					    fn parse(input: ParseStream) -> syn::Result<Self> {
 | 
				
			||||||
 | 
					        if let Ok(inner) = input.parse::<LitStr>() {
 | 
				
			||||||
 | 
					            Ok(ValidAssetsDirTypes::LiteralStr(inner))
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            let inner = input.parse::<Ident>().map_err(|_| {
 | 
				
			||||||
 | 
					                syn::Error::new(
 | 
				
			||||||
 | 
					                    input.span(),
 | 
				
			||||||
 | 
					                    "Assets directory must be a literal string or valid identifier",
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            })?;
 | 
				
			||||||
 | 
					            Ok(ValidAssetsDirTypes::Ident(inner))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct IgnoreDirs(Vec<PathBuf>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct IgnoreDirsWithSpan(Vec<(PathBuf, Span)>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Parse for IgnoreDirsWithSpan {
 | 
				
			||||||
 | 
					    fn parse(input: ParseStream) -> syn::Result<Self> {
 | 
				
			||||||
 | 
					        let inner_content;
 | 
				
			||||||
 | 
					        bracketed!(inner_content in input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut dirs = Vec::new();
 | 
				
			||||||
 | 
					        while !inner_content.is_empty() {
 | 
				
			||||||
 | 
					            let directory_span = inner_content.span();
 | 
				
			||||||
 | 
					            let directory_str = inner_content.parse::<LitStr>()?;
 | 
				
			||||||
 | 
					            if !inner_content.is_empty() {
 | 
				
			||||||
 | 
					                inner_content.parse::<Token![,]>()?;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            let path = PathBuf::from(directory_str.value());
 | 
				
			||||||
 | 
					            dirs.push((path, directory_span));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(IgnoreDirsWithSpan(dirs))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn validate_ignore_dirs(
 | 
				
			||||||
 | 
					    ignore_dirs: IgnoreDirsWithSpan,
 | 
				
			||||||
 | 
					    assets_dir: &ValidAssetsDirTypes,
 | 
				
			||||||
 | 
					) -> syn::Result<IgnoreDirs> {
 | 
				
			||||||
 | 
					    let mut valid_ignore_dirs = Vec::new();
 | 
				
			||||||
 | 
					    for (dir, span) in ignore_dirs.0 {
 | 
				
			||||||
 | 
					        let full_path = PathBuf::from(assets_dir.to_string()).join(&dir);
 | 
				
			||||||
 | 
					        match fs::metadata(&full_path) {
 | 
				
			||||||
 | 
					            Ok(meta) if !meta.is_dir() => {
 | 
				
			||||||
 | 
					                return Err(syn::Error::new(
 | 
				
			||||||
 | 
					                    span,
 | 
				
			||||||
 | 
					                    "The specified ignored directory is not a directory",
 | 
				
			||||||
 | 
					                ));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Ok(_) => valid_ignore_dirs.push(full_path),
 | 
				
			||||||
 | 
					            Err(e) if matches!(e.kind(), std::io::ErrorKind::NotFound) => {
 | 
				
			||||||
 | 
					                return Err(syn::Error::new(
 | 
				
			||||||
 | 
					                    span,
 | 
				
			||||||
 | 
					                    "The specified ignored directory does not exist",
 | 
				
			||||||
 | 
					                ))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Err(e) => {
 | 
				
			||||||
 | 
					                return Err(syn::Error::new(
 | 
				
			||||||
 | 
					                    span,
 | 
				
			||||||
 | 
					                    format!(
 | 
				
			||||||
 | 
					                        "Error reading ignored directory {}: {}",
 | 
				
			||||||
 | 
					                        dir.to_string_lossy(),
 | 
				
			||||||
 | 
					                        DisplayFullError(&e)
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                ))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Ok(IgnoreDirs(valid_ignore_dirs))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ShouldCompress(LitBool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Parse for ShouldCompress {
 | 
				
			||||||
 | 
					    fn parse(input: ParseStream) -> syn::Result<Self> {
 | 
				
			||||||
 | 
					        let lit = input.parse()?;
 | 
				
			||||||
 | 
					        Ok(ShouldCompress(lit))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn generate_static_routes(
 | 
				
			||||||
 | 
					    assets_dir: &ValidAssetsDirTypes,
 | 
				
			||||||
 | 
					    ignore_dirs: &IgnoreDirs,
 | 
				
			||||||
 | 
					    should_compress: &LitBool,
 | 
				
			||||||
 | 
					) -> Result<TokenStream, error::Error> {
 | 
				
			||||||
 | 
					    let assets_dir_abs = Path::new(&assets_dir.to_string())
 | 
				
			||||||
 | 
					        .canonicalize()
 | 
				
			||||||
 | 
					        .map_err(Error::CannotCanonicalizeDirectory)?;
 | 
				
			||||||
 | 
					    let assets_dir_abs_str = assets_dir_abs
 | 
				
			||||||
 | 
					        .to_str()
 | 
				
			||||||
 | 
					        .ok_or(Error::InvalidUnicodeInDirectoryName)?;
 | 
				
			||||||
 | 
					    let canon_ignore_dirs = ignore_dirs
 | 
				
			||||||
 | 
					        .0
 | 
				
			||||||
 | 
					        .iter()
 | 
				
			||||||
 | 
					        .map(|d| d.canonicalize().map_err(Error::CannotCanonicalizeIgnoreDir))
 | 
				
			||||||
 | 
					        .collect::<Result<Vec<_>, _>>()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut routes = Vec::new();
 | 
				
			||||||
 | 
					    for entry in glob(&format!("{assets_dir_abs_str}/**/*")).map_err(Error::Pattern)? {
 | 
				
			||||||
 | 
					        let entry = entry.map_err(Error::Glob)?;
 | 
				
			||||||
 | 
					        let metadata = entry.metadata().map_err(Error::CannotGetMetadata)?;
 | 
				
			||||||
 | 
					        if metadata.is_dir() {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Skip `entry`s which are located in ignored subdirectories
 | 
				
			||||||
 | 
					        if canon_ignore_dirs
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .any(|ignore_dir| entry.starts_with(ignore_dir))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let contents = fs::read(&entry).map_err(Error::CannotReadEntryContents)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Optionally compress files
 | 
				
			||||||
 | 
					        let (maybe_gzip, maybe_zstd) = if should_compress.value {
 | 
				
			||||||
 | 
					            let gzip = gzip_compress(&contents)?;
 | 
				
			||||||
 | 
					            let zstd = zstd_compress(&contents)?;
 | 
				
			||||||
 | 
					            (gzip, zstd)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            (None, None)
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Create parameters for `::static_serve::static_route()`
 | 
				
			||||||
 | 
					        let entry_path = entry
 | 
				
			||||||
 | 
					            .to_str()
 | 
				
			||||||
 | 
					            .ok_or(Error::InvalidUnicodeInEntryName)?
 | 
				
			||||||
 | 
					            .strip_prefix(assets_dir_abs_str)
 | 
				
			||||||
 | 
					            .unwrap_or_default();
 | 
				
			||||||
 | 
					        let content_type = file_content_type(&entry)?;
 | 
				
			||||||
 | 
					        let etag_str = etag(&contents);
 | 
				
			||||||
 | 
					        let lit_byte_str_contents = LitByteStr::new(&contents, Span::call_site());
 | 
				
			||||||
 | 
					        let maybe_gzip = option_to_token_stream_option(maybe_gzip.as_ref());
 | 
				
			||||||
 | 
					        let maybe_zstd = option_to_token_stream_option(maybe_zstd.as_ref());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        routes.push(quote! {
 | 
				
			||||||
 | 
					            router = ::static_serve::static_route(
 | 
				
			||||||
 | 
					                router,
 | 
				
			||||||
 | 
					                #entry_path,
 | 
				
			||||||
 | 
					                #content_type,
 | 
				
			||||||
 | 
					                #etag_str,
 | 
				
			||||||
 | 
					                #lit_byte_str_contents,
 | 
				
			||||||
 | 
					                #maybe_gzip,
 | 
				
			||||||
 | 
					                #maybe_zstd,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(quote! {
 | 
				
			||||||
 | 
					    pub fn static_router<S>() -> ::axum::Router<S>
 | 
				
			||||||
 | 
					        where S: ::std::clone::Clone + ::std::marker::Send + ::std::marker::Sync + 'static {
 | 
				
			||||||
 | 
					            let mut router = ::axum::Router::<S>::new();
 | 
				
			||||||
 | 
					            #(#routes)*
 | 
				
			||||||
 | 
					            router
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn gzip_compress(contents: &[u8]) -> Result<Option<LitByteStr>, Error> {
 | 
				
			||||||
 | 
					    let mut compressor = GzEncoder::new(Vec::new(), flate2::Compression::best());
 | 
				
			||||||
 | 
					    compressor
 | 
				
			||||||
 | 
					        .write_all(contents)
 | 
				
			||||||
 | 
					        .map_err(|e| Error::Gzip(GzipType::CompressorWrite(e)))?;
 | 
				
			||||||
 | 
					    let compressed = compressor
 | 
				
			||||||
 | 
					        .finish()
 | 
				
			||||||
 | 
					        .map_err(|e| Error::Gzip(GzipType::EncoderFinish(e)))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(maybe_get_compressed(&compressed, contents))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn zstd_compress(contents: &[u8]) -> Result<Option<LitByteStr>, Error> {
 | 
				
			||||||
 | 
					    let level = *zstd::compression_level_range().end();
 | 
				
			||||||
 | 
					    let mut encoder = zstd::Encoder::new(Vec::new(), level).unwrap();
 | 
				
			||||||
 | 
					    write_to_zstd_encoder(&mut encoder, contents)
 | 
				
			||||||
 | 
					        .map_err(|e| Error::Zstd(ZstdType::EncoderWrite(e)))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let compressed = encoder
 | 
				
			||||||
 | 
					        .finish()
 | 
				
			||||||
 | 
					        .map_err(|e| Error::Zstd(ZstdType::EncoderFinish(e)))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(maybe_get_compressed(&compressed, contents))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn write_to_zstd_encoder(
 | 
				
			||||||
 | 
					    encoder: &mut zstd::Encoder<'static, Vec<u8>>,
 | 
				
			||||||
 | 
					    contents: &[u8],
 | 
				
			||||||
 | 
					) -> io::Result<()> {
 | 
				
			||||||
 | 
					    encoder.set_pledged_src_size(Some(
 | 
				
			||||||
 | 
					        contents
 | 
				
			||||||
 | 
					            .len()
 | 
				
			||||||
 | 
					            .try_into()
 | 
				
			||||||
 | 
					            .expect("contents size should fit into u64"),
 | 
				
			||||||
 | 
					    ))?;
 | 
				
			||||||
 | 
					    encoder.window_log(23)?;
 | 
				
			||||||
 | 
					    encoder.include_checksum(false)?;
 | 
				
			||||||
 | 
					    encoder.include_contentsize(false)?;
 | 
				
			||||||
 | 
					    encoder.long_distance_matching(false)?;
 | 
				
			||||||
 | 
					    encoder.write_all(contents)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn option_to_token_stream_option<T: ToTokens>(opt: Option<&T>) -> TokenStream {
 | 
				
			||||||
 | 
					    if let Some(inner) = opt {
 | 
				
			||||||
 | 
					        quote! { ::std::option::Option::Some(#inner) }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        quote! { ::std::option::Option::None }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn is_compression_significant(compressed_len: usize, contents_len: usize) -> bool {
 | 
				
			||||||
 | 
					    let ninety_pct_original = contents_len / 10 * 9;
 | 
				
			||||||
 | 
					    compressed_len < ninety_pct_original
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn maybe_get_compressed(compressed: &[u8], contents: &[u8]) -> Option<LitByteStr> {
 | 
				
			||||||
 | 
					    is_compression_significant(compressed.len(), contents.len())
 | 
				
			||||||
 | 
					        .then(|| LitByteStr::new(compressed, Span::call_site()))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn file_content_type(path: &Path) -> Result<&'static str, error::Error> {
 | 
				
			||||||
 | 
					    match path.extension() {
 | 
				
			||||||
 | 
					        Some(ext) if ext.eq_ignore_ascii_case("css") => Ok("text/css"),
 | 
				
			||||||
 | 
					        Some(ext) if ext.eq_ignore_ascii_case("js") => Ok("text/javascript"),
 | 
				
			||||||
 | 
					        Some(ext) if ext.eq_ignore_ascii_case("txt") => Ok("text/plain"),
 | 
				
			||||||
 | 
					        Some(ext) if ext.eq_ignore_ascii_case("woff") => Ok("font/woff"),
 | 
				
			||||||
 | 
					        Some(ext) if ext.eq_ignore_ascii_case("woff2") => Ok("font/woff2"),
 | 
				
			||||||
 | 
					        Some(ext) if ext.eq_ignore_ascii_case("svg") => Ok("image/svg+xml"),
 | 
				
			||||||
 | 
					        ext => Err(error::Error::UnknownFileExtension(ext.map(Into::into))),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn etag(contents: &[u8]) -> String {
 | 
				
			||||||
 | 
					    let sha256 = Sha1::digest(contents);
 | 
				
			||||||
 | 
					    let hash = u64::from_le_bytes(sha256[..8].try_into().unwrap())
 | 
				
			||||||
 | 
					        ^ u64::from_le_bytes(sha256[8..16].try_into().unwrap());
 | 
				
			||||||
 | 
					    format!("\"{hash:016x}\"")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								static-serve/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								static-serve/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "static-serve"
 | 
				
			||||||
 | 
					version.workspace = true
 | 
				
			||||||
 | 
					edition.workspace = true
 | 
				
			||||||
 | 
					license.workspace = true
 | 
				
			||||||
 | 
					rust-version.workspace = true
 | 
				
			||||||
 | 
					keywords.workspace = true
 | 
				
			||||||
 | 
					description.workspace = true
 | 
				
			||||||
 | 
					categories.workspace = true
 | 
				
			||||||
 | 
					repository.workspace = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					static-serve-macro = { path = "../static-serve-macro", version = "0.1.0" }
 | 
				
			||||||
 | 
					axum = { version = "0.8", default-features = false }
 | 
				
			||||||
 | 
					bytes = "1.10"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[lints]
 | 
				
			||||||
 | 
					workspace = true
 | 
				
			||||||
							
								
								
									
										192
									
								
								static-serve/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								static-serve/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,192 @@
 | 
				
			|||||||
 | 
					//! Crate for compressing and embedding static assets
 | 
				
			||||||
 | 
					//! in a web server
 | 
				
			||||||
 | 
					use std::convert::Infallible;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use axum::{
 | 
				
			||||||
 | 
					    extract::FromRequestParts,
 | 
				
			||||||
 | 
					    http::{
 | 
				
			||||||
 | 
					        header::{
 | 
				
			||||||
 | 
					            HeaderValue, ACCEPT_ENCODING, CACHE_CONTROL, CONTENT_ENCODING, CONTENT_TYPE, ETAG,
 | 
				
			||||||
 | 
					            IF_NONE_MATCH, VARY,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        request::Parts,
 | 
				
			||||||
 | 
					        StatusCode,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    response::IntoResponse,
 | 
				
			||||||
 | 
					    routing::get,
 | 
				
			||||||
 | 
					    Router,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use bytes::Bytes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub use static_serve_macro::embed_assets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The accept/reject status for gzip and zstd encoding
 | 
				
			||||||
 | 
					#[derive(Debug, Copy, Clone)]
 | 
				
			||||||
 | 
					struct AcceptEncoding {
 | 
				
			||||||
 | 
					    /// Is gzip accepted?
 | 
				
			||||||
 | 
					    pub gzip: bool,
 | 
				
			||||||
 | 
					    /// Is zstd accepted?
 | 
				
			||||||
 | 
					    pub zstd: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<S> FromRequestParts<S> for AcceptEncoding
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    S: Send + Sync,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type Rejection = Infallible;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
 | 
				
			||||||
 | 
					        let accept_encoding = parts.headers.get(ACCEPT_ENCODING);
 | 
				
			||||||
 | 
					        let accept_encoding = accept_encoding
 | 
				
			||||||
 | 
					            .and_then(|accept_encoding| accept_encoding.to_str().ok())
 | 
				
			||||||
 | 
					            .unwrap_or_default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            gzip: accept_encoding.contains("gzip"),
 | 
				
			||||||
 | 
					            zstd: accept_encoding.contains("zstd"),
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Check if the  `IfNoneMatch` header is present
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					struct IfNoneMatch(Option<HeaderValue>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl IfNoneMatch {
 | 
				
			||||||
 | 
					    /// required function for checking if `IfNoneMatch` is present
 | 
				
			||||||
 | 
					    fn matches(&self, etag: &str) -> bool {
 | 
				
			||||||
 | 
					        self.0
 | 
				
			||||||
 | 
					            .as_ref()
 | 
				
			||||||
 | 
					            .is_some_and(|if_none_match| if_none_match.as_bytes() == etag.as_bytes())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<S> FromRequestParts<S> for IfNoneMatch
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    S: Send + Sync,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type Rejection = Infallible;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
 | 
				
			||||||
 | 
					        let if_none_match = parts.headers.get(IF_NONE_MATCH).cloned();
 | 
				
			||||||
 | 
					        Ok(Self(if_none_match))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[doc(hidden)]
 | 
				
			||||||
 | 
					/// The router for adding routes for static assets
 | 
				
			||||||
 | 
					pub fn static_route<S>(
 | 
				
			||||||
 | 
					    router: Router<S>,
 | 
				
			||||||
 | 
					    web_path: &'static str,
 | 
				
			||||||
 | 
					    content_type: &'static str,
 | 
				
			||||||
 | 
					    etag: &'static str,
 | 
				
			||||||
 | 
					    body: &'static [u8],
 | 
				
			||||||
 | 
					    body_gz: Option<&'static [u8]>,
 | 
				
			||||||
 | 
					    body_zst: Option<&'static [u8]>,
 | 
				
			||||||
 | 
					) -> Router<S>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    S: Clone + Send + Sync + 'static,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    router.route(
 | 
				
			||||||
 | 
					        web_path,
 | 
				
			||||||
 | 
					        get(
 | 
				
			||||||
 | 
					            move |accept_encoding: AcceptEncoding, if_none_match: IfNoneMatch| async move {
 | 
				
			||||||
 | 
					                let headers_base = [
 | 
				
			||||||
 | 
					                    (CONTENT_TYPE, HeaderValue::from_static(content_type)),
 | 
				
			||||||
 | 
					                    (ETAG, HeaderValue::from_static(etag)),
 | 
				
			||||||
 | 
					                    (
 | 
				
			||||||
 | 
					                        CACHE_CONTROL,
 | 
				
			||||||
 | 
					                        HeaderValue::from_static("public, max-age=31536000, immutable"),
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                    (VARY, HeaderValue::from_static("Accept-Encoding")),
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                match (
 | 
				
			||||||
 | 
					                    if_none_match.matches(etag),
 | 
				
			||||||
 | 
					                    accept_encoding.gzip,
 | 
				
			||||||
 | 
					                    accept_encoding.zstd,
 | 
				
			||||||
 | 
					                    body_gz,
 | 
				
			||||||
 | 
					                    body_zst,
 | 
				
			||||||
 | 
					                ) {
 | 
				
			||||||
 | 
					                    (true, _, _, _, _) => (headers_base, StatusCode::NOT_MODIFIED).into_response(),
 | 
				
			||||||
 | 
					                    (false, _, true, _, Some(body_zst)) => (
 | 
				
			||||||
 | 
					                        headers_base,
 | 
				
			||||||
 | 
					                        [(CONTENT_ENCODING, HeaderValue::from_static("zstd"))],
 | 
				
			||||||
 | 
					                        Bytes::from_static(body_zst),
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                        .into_response(),
 | 
				
			||||||
 | 
					                    (false, true, _, Some(body_gz), _) => (
 | 
				
			||||||
 | 
					                        headers_base,
 | 
				
			||||||
 | 
					                        [(CONTENT_ENCODING, HeaderValue::from_static("gzip"))],
 | 
				
			||||||
 | 
					                        Bytes::from_static(body_gz),
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                        .into_response(),
 | 
				
			||||||
 | 
					                    _ => (headers_base, Bytes::from_static(body)).into_response(),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn router_created_with_test_routes_lit_str() {
 | 
				
			||||||
 | 
					        embed_assets!("test_assets/small", compress = false);
 | 
				
			||||||
 | 
					        let router: Router<()> = static_router();
 | 
				
			||||||
 | 
					        assert!(router.has_routes());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn router_created_not_compressed_because_not_worthwhile() {
 | 
				
			||||||
 | 
					        embed_assets!("test_assets/small", compress = true);
 | 
				
			||||||
 | 
					        let router: Router<()> = static_router();
 | 
				
			||||||
 | 
					        assert!(router.has_routes());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn router_created_compressed() {
 | 
				
			||||||
 | 
					        embed_assets!("test_assets/big", compress = true);
 | 
				
			||||||
 | 
					        let router: Router<()> = static_router();
 | 
				
			||||||
 | 
					        assert!(router.has_routes());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn router_created_with_test_routes_ident() {
 | 
				
			||||||
 | 
					        embed_assets!(test_assets, compress = true);
 | 
				
			||||||
 | 
					        let router: Router<()> = static_router();
 | 
				
			||||||
 | 
					        assert!(router.has_routes());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn router_created_ignore_dirs_one() {
 | 
				
			||||||
 | 
					        embed_assets!(test_assets, ignore_dirs = ["test_assets/big"]);
 | 
				
			||||||
 | 
					        let router: Router<()> = static_router();
 | 
				
			||||||
 | 
					        assert!(router.has_routes());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn router_created_ignore_dirs_two() {
 | 
				
			||||||
 | 
					        embed_assets!(
 | 
				
			||||||
 | 
					            test_assets,
 | 
				
			||||||
 | 
					            ignore_dirs = ["test_assets/big", "test_assets/small"]
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let router: Router<()> = static_router();
 | 
				
			||||||
 | 
					        // all directories ignored, so router has no routes
 | 
				
			||||||
 | 
					        assert!(!router.has_routes());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn router_created_ignore_dirs_with_defaults() {
 | 
				
			||||||
 | 
					        // TODO: actually create one of the default ignore directories
 | 
				
			||||||
 | 
					        // in `test_assets` to make sure this works
 | 
				
			||||||
 | 
					        embed_assets!(
 | 
				
			||||||
 | 
					            test_assets,
 | 
				
			||||||
 | 
					            ignore_dirs = ["test_assets/big"],
 | 
				
			||||||
 | 
					            use_default_ignore_dirs = true
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let router: Router<()> = static_router();
 | 
				
			||||||
 | 
					        assert!(router.has_routes());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user