diff --git a/Cargo.lock b/Cargo.lock index c4164bf..1524f7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,6 +124,12 @@ version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + [[package]] name = "arrayvec" version = "0.7.4" @@ -186,6 +192,15 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +[[package]] +name = "base64-simd" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5" +dependencies = [ + "simd-abstraction", +] + [[package]] name = "bindgen" version = "0.68.1" @@ -401,6 +416,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "charming" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c6b6990238a64b4ae139e7085ce2a11815cb67a0c066a3333ce40f3a329be3" +dependencies = [ + "deno_core", + "handlebars", + "image", + "resvg", + "serde", + "serde_json", + "serde_v8", +] + [[package]] name = "chrono" version = "0.4.31" @@ -592,6 +622,19 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" version = "0.5.10" @@ -624,6 +667,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.18" @@ -704,6 +756,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +[[package]] +name = "data-url" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" + [[package]] name = "debugid" version = "0.8.0" @@ -714,6 +772,55 @@ dependencies = [ "uuid", ] +[[package]] +name = "deno_core" +version = "0.232.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229ffd108e028b148a1a5a6122f771bc7c37094170226f44b8b93b3a9b79d114" +dependencies = [ + "anyhow", + "bytes", + "deno_ops", + "deno_unsync", + "futures", + "libc", + "log", + "parking_lot", + "pin-project", + "serde", + "serde_json", + "serde_v8", + "smallvec", + "sourcemap", + "tokio", + "url", + "v8", +] + +[[package]] +name = "deno_ops" +version = "0.108.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7dde627916f8539f3f0d2e754dda40810c8ca4d655f2eaac1ef54785a12fd27" +dependencies = [ + "proc-macro-rules", + "proc-macro2", + "quote", + "strum", + "strum_macros", + "syn 2.0.48", + "thiserror", +] + +[[package]] +name = "deno_unsync" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7557a5e9278b9a5cc8056dc37062ea4344770bda4eeb5973c7cbb7ebf636b9a4" +dependencies = [ + "tokio", +] + [[package]] name = "deranged" version = "0.3.11" @@ -945,6 +1052,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + [[package]] name = "float-ord" version = "0.2.0" @@ -991,6 +1104,29 @@ dependencies = [ "yeslogic-fontconfig-sys", ] +[[package]] +name = "fontconfig-parser" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a595cb550439a117696039dfc69830492058211b771a2a165379f2a1a53d84d" +dependencies = [ + "roxmltree 0.19.0", +] + +[[package]] +name = "fontdb" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020e203f177c0fb250fb19455a252e838d2bbbce1f80f25ecc42402aafa8cd38" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser 0.19.2", +] + [[package]] name = "foreign-types" version = "0.3.2" @@ -1036,6 +1172,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "fslock" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57eafdd0c16f57161105ae1b98a1238f97645f2f588438b2949c99a2af9616bf" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "funty" version = "2.0.0" @@ -1050,6 +1196,7 @@ checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1212,6 +1359,20 @@ dependencies = [ "crunchy", ] +[[package]] +name = "handlebars" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1251,6 +1412,15 @@ dependencies = [ "digest", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "hostname" version = "0.3.1" @@ -1400,6 +1570,12 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + [[package]] name = "image" version = "0.24.7" @@ -1420,6 +1596,12 @@ dependencies = [ "webp", ] +[[package]] +name = "imagesize" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" + [[package]] name = "indexmap" version = "1.9.3" @@ -1533,6 +1715,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kurbo" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b" +dependencies = [ + "arrayvec", +] + [[package]] name = "lalrpop" version = "0.20.0" @@ -1681,6 +1872,15 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +[[package]] +name = "memmap2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.9.0" @@ -1854,6 +2054,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1929,6 +2141,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "outref" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" + [[package]] name = "overload" version = "0.1.1" @@ -2016,6 +2234,51 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "pest_meta" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "petgraph" version = "0.6.4" @@ -2073,6 +2336,32 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2166,6 +2455,29 @@ dependencies = [ "yansi", ] +[[package]] +name = "proc-macro-rules" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f" +dependencies = [ + "proc-macro-rules-macros", + "proc-macro2", + "syn 2.0.48", +] + +[[package]] +name = "proc-macro-rules-macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "207fffb0fe655d1d47f6af98cc2793405e85929bdbc420d685554ff07be27ac7" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "proc-macro2" version = "1.0.75" @@ -2300,6 +2612,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rctree" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f" + [[package]] name = "redox_syscall" version = "0.4.1" @@ -2408,6 +2726,32 @@ dependencies = [ "quick-error", ] +[[package]] +name = "resvg" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7980f653f9a7db31acff916a262c3b78c562919263edea29bf41a056e20497" +dependencies = [ + "gif", + "jpeg-decoder", + "log", + "pico-args", + "png", + "rgb", + "svgtypes", + "tiny-skia", + "usvg", +] + +[[package]] +name = "rgb" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" +dependencies = [ + "bytemuck", +] + [[package]] name = "ring" version = "0.17.7" @@ -2422,6 +2766,21 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "roxmltree" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862340e351ce1b271a378ec53f304a5558f7db87f3769dc655a8f6ecbb68b302" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "roxmltree" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f" + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -2518,9 +2877,11 @@ version = "2024.1.9" dependencies = [ "anyhow", "async-trait", + "charming", "chrono", "chrono-tz", "clap", + "crossbeam", "derivative", "dotenv", "hex", @@ -2554,6 +2915,22 @@ dependencies = [ "url", ] +[[package]] +name = "rustybuzz" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71cd15fef9112a1f94ac64b58d1e4628192631ad6af4dc69997f995459c874e7" +dependencies = [ + "bitflags 1.3.2", + "bytemuck", + "smallvec", + "ttf-parser 0.19.2", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + [[package]] name = "ryu" version = "1.0.16" @@ -2811,6 +3188,21 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_v8" +version = "0.141.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc689cb316d67b200e9f7449ce76cceb7e483e0f828d1a9c3d057c4367b6c26e" +dependencies = [ + "bytes", + "derive_more", + "num-bigint", + "serde", + "smallvec", + "thiserror", + "v8", +] + [[package]] name = "serde_with" version = "1.14.0" @@ -2942,12 +3334,30 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-abstraction" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" +dependencies = [ + "outref", +] + [[package]] name = "simd-adler32" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simplecss" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a11be7c62927d9427e9f40f3444d5499d868648e2edbc4e2116de69e7ec0e89d" +dependencies = [ + "log", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -2978,6 +3388,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" version = "1.11.2" @@ -3004,6 +3423,23 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "sourcemap" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7768edd06c02535e0d50653968f46e1e0d3aa54742190d35dd9466f59de9c71" +dependencies = [ + "base64-simd", + "data-encoding", + "debugid", + "if_chain", + "rustc_version 0.2.3", + "serde", + "serde_json", + "unicode-id-start", + "url", +] + [[package]] name = "spin" version = "0.9.8" @@ -3019,6 +3455,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] + [[package]] name = "string_cache" version = "0.8.7" @@ -3049,12 +3494,44 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", +] + [[package]] name = "subtle" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +[[package]] +name = "svgtypes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71499ff2d42f59d26edb21369a308ede691421f79ebc0f001e2b1fd3a7c9e52" +dependencies = [ + "kurbo", + "siphasher", +] + [[package]] name = "syn" version = "1.0.109" @@ -3225,6 +3702,32 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -3448,6 +3951,12 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff" +[[package]] +name = "ttf-parser" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49d64318d8311fc2668e48b63969f4343e0a85c4a109aa8460d6672e364b8bd1" + [[package]] name = "ttf-parser" version = "0.20.0" @@ -3525,6 +4034,12 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "uname" version = "0.1.1" @@ -3549,6 +4064,24 @@ version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +[[package]] +name = "unicode-bidi-mirroring" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694" + +[[package]] +name = "unicode-ccc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1" + +[[package]] +name = "unicode-id-start" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f73150333cb58412db36f2aca8f2875b013049705cc77b94ded70a1ab1f5da" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -3564,6 +4097,24 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-properties" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" + +[[package]] +name = "unicode-script" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8d71f5726e5f285a935e9fe8edfd53f0491eb6e9a5774097fdabee7cd8c9cd" + +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + [[package]] name = "unicode-xid" version = "0.2.4" @@ -3603,6 +4154,67 @@ dependencies = [ "serde", ] +[[package]] +name = "usvg" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51daa774fe9ee5efcf7b4fec13019b8119cda764d9a8b5b06df02bb1445c656" +dependencies = [ + "base64 0.21.5", + "log", + "pico-args", + "usvg-parser", + "usvg-text-layout", + "usvg-tree", + "xmlwriter", +] + +[[package]] +name = "usvg-parser" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45c88a5ffaa338f0e978ecf3d4e00d8f9f493e29bed0752e1a808a1db16afc40" +dependencies = [ + "data-url", + "flate2", + "imagesize", + "kurbo", + "log", + "roxmltree 0.18.1", + "simplecss", + "siphasher", + "svgtypes", + "usvg-tree", +] + +[[package]] +name = "usvg-text-layout" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d2374378cb7a3fb8f33894e0fdb8625e1bbc4f25312db8d91f862130b541593" +dependencies = [ + "fontdb", + "kurbo", + "log", + "rustybuzz", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "usvg-tree", +] + +[[package]] +name = "usvg-tree" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cacb0c5edeaf3e80e5afcf5b0d4004cc1d36318befc9a7c6606507e5d0f4062" +dependencies = [ + "rctree", + "strict-num", + "svgtypes", + "tiny-skia-path", +] + [[package]] name = "utf-8" version = "0.7.6" @@ -3625,6 +4237,18 @@ dependencies = [ "serde", ] +[[package]] +name = "v8" +version = "0.81.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75f5f378b9b54aff3b10da8170d26af4cfd217f644cf671badcd13af5db4beb" +dependencies = [ + "bitflags 1.3.2", + "fslock", + "once_cell", + "which", +] + [[package]] name = "valuable" version = "0.1.0" @@ -3778,6 +4402,18 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "widestring" version = "1.0.2" @@ -3984,6 +4620,18 @@ dependencies = [ "tap", ] +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + [[package]] name = "xxhash-rust" version = "0.8.8" diff --git a/Cargo.toml b/Cargo.toml index e84e07f..b4ce4fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ memory_db = [] plot_matplotlib = ["inline-python"] plot_plotters = ["plotters", "png"] +plot_charming = ["charming", "crossbeam"] plot_plotters_static = ["plot_plotters", "plotters/ab_glyph"] plot_plotters_dynamic = ["plot_plotters", "plotters/ttf"] @@ -59,6 +60,16 @@ inline-python = { version = "0.12", optional = true } # plot_plotters png = { version = "0.17", optional = true } +# plot_charming +crossbeam = { version = "0.8", optional = true } + +[dependencies.charming] +version = "0.3" +optional = true +default-features = false +features = ["ssr"] + + [dependencies.serenity] version = "0.12" optional = true diff --git a/src/bot/genkai_point/mod.rs b/src/bot/genkai_point/mod.rs index 76d1576..9ce9468 100644 --- a/src/bot/genkai_point/mod.rs +++ b/src/bot/genkai_point/mod.rs @@ -18,7 +18,7 @@ use { chrono::{DateTime, Duration, Utc}, clap::ValueEnum, once_cell::sync::Lazy, - std::{cmp::Ordering, collections::HashMap, fmt::Write}, + std::{cmp::Ordering, collections::HashMap, fmt::Write, future::Future}, tokio::sync::Mutex, }; @@ -160,7 +160,7 @@ pub(crate) trait GenkaiPointDatabase: Send + Sync { } pub(crate) trait Plotter: Send + Sync + 'static { - fn plot(&self, data: Vec<(String, Vec)>) -> Result>; + fn plot(&self, data: Vec<(String, Vec)>) -> impl Future>> + Send; } #[derive(Debug)] diff --git a/src/bot/genkai_point/plot/charming.rs b/src/bot/genkai_point/plot/charming.rs new file mode 100644 index 0000000..df12728 --- /dev/null +++ b/src/bot/genkai_point/plot/charming.rs @@ -0,0 +1,126 @@ +use { + crate::bot::genkai_point::plot::Plotter, + anyhow::{anyhow, Result}, + charming::{ + component::Axis, element::name_location::NameLocation, series::Line, Chart, ImageFormat, + ImageRenderer, + }, + crossbeam::channel::{Receiver, Sender}, + std::thread, + tokio::sync::oneshot, +}; + +pub(crate) struct Charming { + renderer: Renderer, +} + +impl Charming { + pub(crate) fn new() -> Self { + let renderer = Renderer::spawn(); + + Self { renderer } + } +} + +impl Plotter for Charming { + async fn plot(&self, data: Vec<(String, Vec)>) -> Result> { + let chart = data + .iter() + .fold(Chart::new(), |chart, (label, data)| { + chart.series(Line::new().name(label).data(data.clone())) + }) + .background_color("#FFFFFF") + .x_axis( + Axis::new() + .name_location(NameLocation::Center) + .name("時間経過(日)"), + ) + .y_axis( + Axis::new() + .name_location(NameLocation::Center) + .name("累計VC時間(時)"), + ); + + self.renderer.render(chart).await + } +} + +struct Request { + data: Chart, + bell: oneshot::Sender, +} +struct Response { + image: Result>, +} + +struct Renderer { + tx: Sender, + _thread_handle: thread::JoinHandle<()>, +} + +impl Renderer { + fn render_thread(rx: Receiver) { + let mut renderer = ImageRenderer::new(1280, 720); + + for req in rx { + let image = renderer + .render_format(ImageFormat::Png, &req.data) + .map_err(|e| anyhow!("charming error: {e:#?}")); + + req.bell.send(Response { image }).ok(); + } + } + + fn spawn() -> Self { + let (tx, rx) = crossbeam::channel::unbounded::(); + + let handle = std::thread::spawn(|| Self::render_thread(rx)); + + Self { + tx, + _thread_handle: handle, + } + } + + async fn render(&self, data: Chart) -> Result> { + let (tx, rx) = oneshot::channel(); + + self.tx.send(Request { data, bell: tx }).unwrap(); + + rx.await.unwrap().image + } +} + +#[tokio::test] +async fn test() { + let charming = std::sync::Arc::new(Charming::new()); + + let mut handles = vec![]; + + #[allow(unused_variables)] + for i in 0..10 { + let charming = charming.clone(); + + handles.push(tokio::spawn(async move { + let result = charming + .plot(vec![ + ("kawaemon".into(), vec![1.0, 4.0, 6.0, 7.0]), + ("kawak".into(), vec![2.0, 5.0, 11.0, 14.0]), + ]) + .await + .unwrap(); + + // should we assert_eq with actual png? + assert_ne!(result.len(), 0); + + // uncomment this to see image artifacts + // tokio::fs::write(format!("./out{i}.png"), result) + // .await + // .unwrap(); + })); + } + + for h in handles { + h.await.unwrap(); + } +} diff --git a/src/bot/genkai_point/plot/matplotlib.rs b/src/bot/genkai_point/plot/matplotlib.rs index bf6a6e1..08bcebc 100644 --- a/src/bot/genkai_point/plot/matplotlib.rs +++ b/src/bot/genkai_point/plot/matplotlib.rs @@ -20,7 +20,7 @@ impl Matplotlib { } impl Plotter for Matplotlib { - fn plot(&self, data: Vec<(String, Vec)>) -> Result> { + async fn plot(&self, data: Vec<(String, Vec)>) -> Result> { let result: Result = std::panic::catch_unwind(|| { python! { import io @@ -47,12 +47,14 @@ impl Plotter for Matplotlib { } } -#[test] -fn test_plot_to_image() { - let result = Matplotlib.plot(vec![ - ("kawaemon".into(), vec![1.0, 4.0, 6.0, 7.0]), - ("kawak".into(), vec![2.0, 5.0, 11.0, 14.0]), - ]); +#[tokio::test] +async fn test_plot_to_image() { + let result = Matplotlib {} + .plot(vec![ + ("kawaemon".into(), vec![1.0, 4.0, 6.0, 7.0]), + ("kawak".into(), vec![2.0, 5.0, 11.0, 14.0]), + ]) + .await; // should we assert_eq with actual png? assert_ne!(result.unwrap().len(), 0); diff --git a/src/bot/genkai_point/plot/mod.rs b/src/bot/genkai_point/plot/mod.rs index de8c474..51b9bf3 100644 --- a/src/bot/genkai_point/plot/mod.rs +++ b/src/bot/genkai_point/plot/mod.rs @@ -15,6 +15,9 @@ pub(crate) mod matplotlib; #[cfg(feature = "plot_plotters")] pub(crate) mod plotters; +#[cfg(feature = "plot_charming")] +pub(crate) mod charming; + pub(super) async fn plot( db: &impl GenkaiPointDatabase, ctx: &dyn Context, @@ -80,6 +83,7 @@ pub(super) async fn plot( // use tokio::task::spawn_blocking to solve this problem. let image = plotter .plot(prottable_data) + .await .context("failed to plot graph")?; Ok(Some(image)) diff --git a/src/bot/genkai_point/plot/plotters.rs b/src/bot/genkai_point/plot/plotters.rs index eaba281..62f3c57 100644 --- a/src/bot/genkai_point/plot/plotters.rs +++ b/src/bot/genkai_point/plot/plotters.rs @@ -32,7 +32,7 @@ impl Plotters { } impl Plotter for Plotters { - fn plot(&self, data: Vec<(String, Vec)>) -> Result> { + async fn plot(&self, data: Vec<(String, Vec)>) -> Result> { const SIZE: (usize, usize) = (1280, 720); let mut buffer = vec![0; SIZE.0 * SIZE.1 * 3]; @@ -108,13 +108,14 @@ impl Plotter for Plotters { } } -#[test] -fn test() { +#[tokio::test] +async fn test() { let result = Plotters::new() .plot(vec![ ("kawaemon".into(), vec![1.0, 4.0, 6.0, 7.0]), ("kawak".into(), vec![2.0, 5.0, 11.0, 14.0]), ]) + .await .unwrap(); // should we assert_eq with actual png? diff --git a/src/main.rs b/src/main.rs index 240bc21..2ef1ced 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ use { assert_one_feature!("discord_client", "console_client"); assert_one_feature!("mongo_db", "memory_db"); -assert_one_feature!("plot_plotters", "plot_matplotlib"); +assert_one_feature!("plot_plotters", "plot_matplotlib", "plot_charming"); fn setup_sentry() -> Option { let Ok(sentry_dsn) = env_var("SENTRY_DSN") else { @@ -74,7 +74,9 @@ async fn async_main() -> Result<()> { #[cfg(feature = "plot_plotters")] let plotter = plot::plotters::Plotters::new(); #[cfg(feature = "plot_matplotlib")] - let plotter = plot::plotters::Matplotlib::new(); + let plotter = plot::matplotlib::Matplotlib::new(); + #[cfg(feature = "plot_charming")] + let plotter = plot::charming::Charming::new(); let pgp_whitelist = env_var("PGP_SOURCE_DOMAIN_WHITELIST")? .split(',') @@ -121,6 +123,56 @@ macro_rules! assert_one_feature { " feature." )); }; + ($a:literal, $b:literal, $c:literal) => { + #[cfg(all(feature = $a, feature = $b, feature = $c))] + compile_error!(concat!( + "You can't enable both of ", + $a, + " and ", + $b, + " and ", + $c, + " feature at the same time." + )); + + #[cfg(all(feature = $a, feature = $b))] + compile_error!(concat!( + "You can't enable both of ", + $a, + " and ", + $b, + " feature at the same time." + )); + + #[cfg(all(feature = $b, feature = $c))] + compile_error!(concat!( + "You can't enable both of ", + $b, + " and ", + $c, + " feature at the same time." + )); + + #[cfg(all(feature = $c, feature = $a))] + compile_error!(concat!( + "You can't enable both of ", + $c, + " and ", + $a, + " feature at the same time." + )); + + #[cfg(not(any(feature = $a, feature = $b, feature = $c)))] + compile_error!(concat!( + "You must enable either ", + $a, + " or ", + $b, + " or ", + $c, + " feature." + )); + }; } use assert_one_feature;