From c3cc5c9d03bcfba193daac5ec0729da748f2e953 Mon Sep 17 00:00:00 2001 From: alyssa Date: Fri, 13 Sep 2024 16:02:30 +0900 Subject: [PATCH 1/9] init rust command parser --- .gitignore | 3 +- Cargo.lock | 381 ++++++++++++++++-- Cargo.toml | 1 + .../CommandSystem/Context/Context.cs | 14 +- PluralKit.Bot/CommandSystem/ParametersFFI.cs | 66 +++ PluralKit.Bot/PluralKit.Bot.csproj | 1 + lib/command_system_macros/Cargo.toml | 7 + lib/command_system_macros/src/lib.rs | 109 +++++ lib/commands/Cargo.toml | 16 + lib/commands/build.rs | 3 + lib/commands/src/commands.udl | 13 + lib/commands/src/lib.rs | 208 ++++++++++ lib/commands/src/string.rs | 87 ++++ lib/commands/src/token.rs | 84 ++++ lib/commands/uniffi.toml | 2 + 15 files changed, 968 insertions(+), 27 deletions(-) create mode 100644 PluralKit.Bot/CommandSystem/ParametersFFI.cs create mode 100644 lib/command_system_macros/Cargo.toml create mode 100644 lib/command_system_macros/src/lib.rs create mode 100644 lib/commands/Cargo.toml create mode 100644 lib/commands/build.rs create mode 100644 lib/commands/src/commands.udl create mode 100644 lib/commands/src/lib.rs create mode 100644 lib/commands/src/string.rs create mode 100644 lib/commands/src/token.rs create mode 100644 lib/commands/uniffi.toml diff --git a/.gitignore b/.gitignore index d3ef7ada..94e68792 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,5 @@ pluralkit.*.conf logs/ .version recipe.json -.docker-bin/ \ No newline at end of file +.docker-bin/ +PluralKit.Bot/commands.cs diff --git a/Cargo.lock b/Cargo.lock index 76f6764f..abc1e061 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,6 +112,47 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f907281554a3d0312bb7aab855a8e0ef6cbf1614d06de54105039ca8b34460e" +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn 2.0.77", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + [[package]] name = "async-trait" version = "0.1.80" @@ -120,7 +161,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.77", ] [[package]] @@ -293,6 +334,24 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -354,6 +413,38 @@ dependencies = [ "either", ] +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cc" version = "1.0.98" @@ -378,6 +469,19 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "command_system_macros" +version = "0.1.0" + +[[package]] +name = "commands" +version = "0.1.0" +dependencies = [ + "command_system_macros", + "lazy_static", + "uniffi", +] + [[package]] name = "config" version = "0.13.3" @@ -572,7 +676,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.77", ] [[package]] @@ -697,6 +801,15 @@ dependencies = [ "url", ] +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + [[package]] name = "futures" version = "0.3.30" @@ -764,7 +877,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.77", ] [[package]] @@ -834,6 +947,23 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "goblin" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1374,9 +1504,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" @@ -1451,6 +1581,16 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1585,6 +1725,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "oneshot-uniffi" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c" + [[package]] name = "opaque-debug" version = "0.3.0" @@ -1795,6 +1941,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "portable-atomic" version = "0.3.19" @@ -1824,7 +1976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.66", + "syn 2.0.77", ] [[package]] @@ -1863,7 +2015,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.66", + "syn 2.0.77", "tempfile", ] @@ -1877,7 +2029,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.77", ] [[package]] @@ -2051,14 +2203,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.4" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.7", - "regex-syntax 0.7.5", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -2072,13 +2224,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.7" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax 0.8.4", ] [[package]] @@ -2089,9 +2241,9 @@ checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" @@ -2289,11 +2441,34 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "semver" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +dependencies = [ + "serde", +] [[package]] name = "serde" @@ -2312,7 +2487,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.77", ] [[package]] @@ -2410,6 +2585,12 @@ dependencies = [ "rand_core", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "sketches-ddsketch" version = "0.2.0" @@ -2684,6 +2865,12 @@ dependencies = [ "urlencoding", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stringprep" version = "0.1.5" @@ -2714,9 +2901,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -2829,7 +3016,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.77", ] [[package]] @@ -3036,6 +3223,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.10" @@ -3075,6 +3271,134 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "uniffi" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21345172d31092fd48c47fd56c53d4ae9e41c4b1f559fb8c38c1ab1685fd919f" +dependencies = [ + "anyhow", + "uniffi_build", + "uniffi_core", + "uniffi_macros", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd992f2929a053829d5875af1eff2ee3d7a7001cb3b9a46cc7895f2caede6940" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "fs-err", + "glob", + "goblin", + "heck 0.4.1", + "once_cell", + "paste", + "serde", + "toml", + "uniffi_meta", + "uniffi_testing", + "uniffi_udl", +] + +[[package]] +name = "uniffi_build" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "001964dd3682d600084b3aaf75acf9c3426699bc27b65e96bb32d175a31c74e9" +dependencies = [ + "anyhow", + "camino", + "uniffi_bindgen", +] + +[[package]] +name = "uniffi_checksum_derive" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55137c122f712d9330fd985d66fa61bdc381752e89c35708c13ce63049a3002c" +dependencies = [ + "quote", + "syn 2.0.77", +] + +[[package]] +name = "uniffi_core" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6121a127a3af1665cd90d12dd2b3683c2643c5103281d0fed5838324ca1fad5b" +dependencies = [ + "anyhow", + "bytes", + "camino", + "log", + "once_cell", + "oneshot-uniffi", + "paste", + "static_assertions", +] + +[[package]] +name = "uniffi_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11cf7a58f101fcedafa5b77ea037999b88748607f0ef3a33eaa0efc5392e92e4" +dependencies = [ + "bincode", + "camino", + "fs-err", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn 2.0.77", + "toml", + "uniffi_build", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71dc8573a7b1ac4b71643d6da34888273ebfc03440c525121f1b3634ad3417a2" +dependencies = [ + "anyhow", + "bytes", + "siphasher", + "uniffi_checksum_derive", +] + +[[package]] +name = "uniffi_testing" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "118448debffcb676ddbe8c5305fb933ab7e0123753e659a71dc4a693f8d9f23c" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "fs-err", + "once_cell", +] + +[[package]] +name = "uniffi_udl" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "889edb7109c6078abe0e53e9b4070cf74a6b3468d141bdf5ef1bd4d1dc24a1c3" +dependencies = [ + "anyhow", + "uniffi_meta", + "uniffi_testing", + "weedle2", +] + [[package]] name = "untrusted" version = "0.9.0" @@ -3165,7 +3489,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.77", "wasm-bindgen-shared", ] @@ -3199,7 +3523,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3229,6 +3553,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weedle2" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e79c5206e1f43a2306fd64bdb95025ee4228960f2e6c5a8b173f3caaf807741" +dependencies = [ + "nom", +] + [[package]] name = "whoami" version = "1.5.1" @@ -3555,7 +3888,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.77", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cd075886..3866b321 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "./lib/libpk", + "./lib/commands", "./services/api", "./services/dispatch" ] diff --git a/PluralKit.Bot/CommandSystem/Context/Context.cs b/PluralKit.Bot/CommandSystem/Context/Context.cs index 99d4a39b..f5a6c9fb 100644 --- a/PluralKit.Bot/CommandSystem/Context/Context.cs +++ b/PluralKit.Bot/CommandSystem/Context/Context.cs @@ -45,9 +45,19 @@ public class Context _provider = provider; _commandMessageService = provider.Resolve(); CommandPrefix = message.Content?.Substring(0, commandParseOffset); - Parameters = new Parameters(message.Content?.Substring(commandParseOffset)); Rest = provider.Resolve(); Cluster = provider.Resolve(); + + try + { + Parameters = new ParametersFFI(message.Content?.Substring(commandParseOffset)); + } + catch (PKError e) + { + // todo: not this + Reply($"{Emojis.Error} {e.Message}"); + throw; + } } public readonly IDiscordCache Cache; @@ -71,7 +81,7 @@ public class Context public DateTimeZone Zone => Config?.Zone ?? DateTimeZone.Utc; public readonly string CommandPrefix; - public readonly Parameters Parameters; + public readonly ParametersFFI Parameters; internal readonly IDatabase Database; internal readonly ModelRepository Repository; diff --git a/PluralKit.Bot/CommandSystem/ParametersFFI.cs b/PluralKit.Bot/CommandSystem/ParametersFFI.cs new file mode 100644 index 00000000..dcd1097b --- /dev/null +++ b/PluralKit.Bot/CommandSystem/ParametersFFI.cs @@ -0,0 +1,66 @@ +using uniffi.commands; + +namespace PluralKit.Bot; + +public class ParametersFFI +{ + private string _cb { get; init; } + private List _args { get; init; } + public int _ptr = -1; + private Dictionary _flags { get; init; } + + // just used for errors, temporarily + public string FullCommand { get; init; } + + public ParametersFFI(string cmd) + { + FullCommand = cmd; + var result = CommandsMethods.ParseCommand(cmd); + if (result is CommandResult.Ok) + { + var command = ((CommandResult.Ok)result).@command; + _cb = command.@commandRef; + _args = command.@args; + _flags = command.@flags; + } + else + { + throw new PKError(((CommandResult.Err)result).@error); + } + } + + public string Pop() + { + if (_args.Count > _ptr + 1) Console.WriteLine($"pop: {_ptr + 1}, {_args[_ptr + 1]}"); + else Console.WriteLine("pop: no more arguments"); + if (_args.Count() == _ptr + 1) return ""; + _ptr++; + return _args[_ptr]; + } + + public string Peek() + { + if (_args.Count > _ptr + 1) Console.WriteLine($"peek: {_ptr + 1}, {_args[_ptr + 1]}"); + else Console.WriteLine("peek: no more arguments"); + if (_args.Count() == _ptr + 1) return ""; + return _args[_ptr + 1]; + } + + // this might not work quite right + public string PeekWithPtr(ref int ptr) + { + return _args[ptr]; + } + + public ISet Flags() + { + return new HashSet(_flags.Keys); + } + + // parsed differently in new commands, does this work right? + // note: skipFlags here does nothing + public string Remainder(bool skipFlags = false) + { + return Pop(); + } +} \ No newline at end of file diff --git a/PluralKit.Bot/PluralKit.Bot.csproj b/PluralKit.Bot/PluralKit.Bot.csproj index 479a50a1..27e61fa3 100644 --- a/PluralKit.Bot/PluralKit.Bot.csproj +++ b/PluralKit.Bot/PluralKit.Bot.csproj @@ -4,6 +4,7 @@ Exe net6.0 annotations + true enable diff --git a/lib/command_system_macros/Cargo.toml b/lib/command_system_macros/Cargo.toml new file mode 100644 index 00000000..cf660792 --- /dev/null +++ b/lib/command_system_macros/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "command_system_macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true diff --git a/lib/command_system_macros/src/lib.rs b/lib/command_system_macros/src/lib.rs new file mode 100644 index 00000000..854844c6 --- /dev/null +++ b/lib/command_system_macros/src/lib.rs @@ -0,0 +1,109 @@ +use proc_macro::{Delimiter, TokenStream, TokenTree}; + +fn make_command(tokens: Vec, help: String, cb: String) -> String { + let tokens = tokens + .iter() + .map(|v| format!("Token::{v}")) + .collect::>() + .join(","); + format!( + r#"Command {{ tokens: vec![{tokens}], help: {help}.to_string(), cb: "{cb}".to_string() }}"# + ) +} + +fn command_from_stream(stream: TokenStream) -> String { + let mut part = 0; + let mut found_tokens: Vec = Vec::new(); + let mut found_cb: Option = None; + let mut found_help: Option = None; + + let mut is_token_lit = false; + let mut tokens = stream.clone().into_iter(); + 'a: loop { + let cur_token = tokens.next(); + match cur_token { + None if part == 2 && found_help.is_some() => break 'a, + Some(TokenTree::Ident(ident)) if part == 0 => { + found_tokens.push(if is_token_lit { + format!("{ident}") + } else { + format!("Value(vec![\"{ident}\".to_string()])") + }); + // reset this + is_token_lit = false; + } + Some(TokenTree::Punct(punct)) if part == 0 && format!("{punct}") == "@" => { + is_token_lit = true + } + Some(TokenTree::Punct(punct)) + if ((part == 0 && found_tokens.len() > 0) || (part == 1 && found_cb.is_some())) + && format!("{punct}") == "," => + { + part += 1 + } + Some(TokenTree::Ident(ident)) if part == 1 => found_cb = Some(format!("{ident}")), + Some(TokenTree::Literal(lit)) if part == 2 => found_help = Some(format!("{lit}")), + _ => panic!("invalid command definition: {stream}"), + } + } + make_command(found_tokens, found_help.unwrap(), found_cb.unwrap()) +} + +#[proc_macro] +pub fn commands(stream: TokenStream) -> TokenStream { + let mut commands: Vec = Vec::new(); + + let mut top_level_tokens = stream.into_iter(); + 'a: loop { + // "command" + match top_level_tokens.next() { + Some(TokenTree::Ident(ident)) if format!("{ident}") == "command" => {} + None => break 'a, + _ => panic!("contents of commands! macro is invalid"), + } + // + match top_level_tokens.next() { + Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Parenthesis => { + commands.push(command_from_stream(group.stream())); + } + _ => panic!("contents of commands! macro is invalid"), + } + // ; + match top_level_tokens.next() { + Some(TokenTree::Punct(punct)) if format!("{punct}") == ";" => {} + _ => panic!("contents of commands! macro is invalid"), + } + } + + let command_registrations = commands + .iter() + .map(|v| format!("tree.register_command({v});")) + .collect::>() + .join("\n"); + + let res = format!( + r#" +lazy_static::lazy_static! {{ + static ref COMMAND_TREE: TreeBranch = {{ + let mut tree = TreeBranch {{ + current_command_key: None, + possible_tokens: vec![], + branches: HashMap::new(), + }}; + + {command_registrations} + + tree.sort_tokens(); + + // println!("{{tree:#?}}"); + + tree + }}; +}} + "# + ); + + // panic!("{res}"); + + res.parse().unwrap() +} diff --git a/lib/commands/Cargo.toml b/lib/commands/Cargo.toml new file mode 100644 index 00000000..1d1ac480 --- /dev/null +++ b/lib/commands/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "commands" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +lazy_static = { workspace = true } +command_system_macros = { path = "../command_system_macros" } + +uniffi = { version = "0.25" } + +[build-dependencies] +uniffi = { version = "0.25", features = [ "build" ] } diff --git a/lib/commands/build.rs b/lib/commands/build.rs new file mode 100644 index 00000000..3f31f453 --- /dev/null +++ b/lib/commands/build.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi::generate_scaffolding("src/commands.udl").unwrap(); +} diff --git a/lib/commands/src/commands.udl b/lib/commands/src/commands.udl new file mode 100644 index 00000000..cc7af428 --- /dev/null +++ b/lib/commands/src/commands.udl @@ -0,0 +1,13 @@ +namespace commands { + CommandResult parse_command(string input); +}; +[Enum] +interface CommandResult { + Ok(ParsedCommand command); + Err(string error); +}; +dictionary ParsedCommand { + string command_ref; + sequence args; + record flags; +}; diff --git a/lib/commands/src/lib.rs b/lib/commands/src/lib.rs new file mode 100644 index 00000000..0217dec7 --- /dev/null +++ b/lib/commands/src/lib.rs @@ -0,0 +1,208 @@ +#![feature(let_chains)] + +use core::panic; +use std::{cmp::Ordering, collections::HashMap}; + +uniffi::include_scaffolding!("commands"); + +mod string; +mod token; +use token::*; + +use command_system_macros::commands; + +// todo!: move all this stuff into a different file +// lib.rs should just have exported symbols and command definitions + +#[derive(Debug, Clone)] +struct TreeBranch { + current_command_key: Option, + /// branches.keys(), but sorted by specificity + possible_tokens: Vec, + branches: HashMap, +} + +impl TreeBranch { + fn register_command(&mut self, command: Command) { + let mut current_branch = self; + // iterate over tokens in command + for token in command.tokens { + // recursively get or create a sub-branch for each token + current_branch = current_branch.branches.entry(token).or_insert(TreeBranch { + current_command_key: None, + possible_tokens: vec![], + branches: HashMap::new(), + }) + } + // when we're out of tokens, add an Empty branch with the callback and no sub-branches + current_branch.branches.insert( + Token::Empty, + TreeBranch { + current_command_key: Some(command.cb), + possible_tokens: vec![], + branches: HashMap::new(), + }, + ); + } + + fn sort_tokens(&mut self) { + for branch in self.branches.values_mut() { + branch.sort_tokens(); + } + + // put Value tokens at the end + // i forget exactly how this works + // todo!: document this before PR mergs + self.possible_tokens = self + .branches + .keys() + .into_iter() + .map(|v| v.clone()) + .collect(); + self.possible_tokens.sort_by(|v, _| { + if matches!(v, Token::Value(_)) { + Ordering::Greater + } else { + Ordering::Less + } + }); + } +} + +struct Command { + tokens: Vec, + help: String, + cb: String, +} + +// todo: aliases +// todo: categories +commands! { + command(help, help, "Shows the help command"); + + command(member new, member_new, "Creates a new system member"); + command(member @MemberRef, member_show, "Shows information about a member"); + command(member @MemberRef description, member_desc_show, "Shows a member's description"); + command(member @MemberRef description @FullString, member_desc_update, "Changes a member's description"); + command(member @MemberRef privacy, member_privacy_show, "Displays a member's current privacy settings"); + command(member @MemberRef privacy @MemberPrivacyTarget @PrivacyLevel, member_privacy_update, "Changes a member's privacy settings"); +} + +pub enum CommandResult { + Ok { command: ParsedCommand }, + Err { error: String }, +} + +pub struct ParsedCommand { + pub command_ref: String, + pub args: Vec, + pub flags: HashMap>, +} + +/// Find the next token from an either raw or partially parsed command string +/// +/// Returns: +/// - matched token, to move deeper into the tree +/// - matched value (if this command matched an user-provided value such as a member name) +/// - end position of matched token +/// - optionally a short-circuit error +fn next_token( + possible_tokens: Vec, + input: String, + current_pos: usize, +) -> Result<(Token, Option, usize), Option> { + // get next parameter, matching quotes + let param = crate::string::next_param(input.clone(), current_pos); + println!("matched: {param:?}\n---"); + + // try checking if this is a flag + // todo!: this breaks full text matching if the full text starts with a flag + // (but that's kinda already broken anyway) + if let Some((value, new_pos)) = param.clone() + && value.starts_with('-') + { + return Ok(( + Token::Flag, + Some(value.trim_start_matches('-').to_string()), + new_pos, + )); + } + + // iterate over tokens and run try_match + for token in possible_tokens { + if let TokenMatchResult::Match(value) = + // for FullString just send the whole string + token.try_match(if matches!(token, Token::FullString) { + if input.is_empty() { + None + } else { + Some(input.clone()) + } + } else { + param.clone().map(|v| v.0) + }) + { + return Ok((token, value, param.map(|v| v.1).unwrap_or(current_pos))); + } + } + + Err(None) +} + +fn parse_command(input: String) -> CommandResult { + let mut local_tree: TreeBranch = COMMAND_TREE.clone(); + + // end position of all currently matched tokens + let mut current_pos = 0; + + let mut args: Vec = Vec::new(); + let mut flags: HashMap> = HashMap::new(); + + loop { + match next_token( + local_tree.possible_tokens.clone(), + input.clone(), + current_pos, + ) { + Ok((found_token, arg, new_pos)) => { + current_pos = new_pos; + if let Token::Flag = found_token { + flags.insert(arg.unwrap(), None); + // don't try matching flags as tree elements + continue; + } + + if let Some(arg) = arg { + args.push(arg); + } + + if let Some(next_tree) = local_tree.branches.get(&found_token) { + local_tree = next_tree.clone(); + } else { + panic!("found token could not match tree, at {input}"); + } + } + Err(None) => { + if let Some(command_ref) = local_tree.current_command_key { + return CommandResult::Ok { + command: ParsedCommand { + command_ref, + args, + flags, + }, + }; + } + // todo: check if last token is a common incorrect unquote (multi-member names etc) + // todo: check if this is a system name in pk;s command + return CommandResult::Err { + error: "Command not found.".to_string(), + }; + } + Err(Some(short_circuit)) => { + return CommandResult::Err { + error: short_circuit, + }; + } + } + } +} diff --git a/lib/commands/src/string.rs b/lib/commands/src/string.rs new file mode 100644 index 00000000..bc65c8a0 --- /dev/null +++ b/lib/commands/src/string.rs @@ -0,0 +1,87 @@ +use std::collections::HashMap; + +lazy_static::lazy_static! { + // Dictionary of (left, right) quote pairs + // Each char in the string is an individual quote, multi-char strings imply "one of the following chars" + pub static ref QUOTE_PAIRS: HashMap = { + let mut pairs = HashMap::new(); + + macro_rules! insert_pair { + ($a:literal, $b:literal) => { + pairs.insert($a.to_string(), $b.to_string()); + // make it easier to look up right quotes + for char in $a.chars() { + pairs.insert(char.to_string(), $b.to_string()); + } + } + } + + // Basic + insert_pair!( "'", "'" ); // ASCII single quotes + insert_pair!( "\"", "\"" ); // ASCII double quotes + + // "Smart quotes" + // Specifically ignore the left/right status of the quotes and match any combination of them + // Left string also includes "low" quotes to allow for the low-high style used in some locales + insert_pair!( "\u{201C}\u{201D}\u{201F}\u{201E}", "\u{201C}\u{201D}\u{201F}" ); // double quotes + insert_pair!( "\u{2018}\u{2019}\u{201B}\u{201A}", "\u{2018}\u{2019}\u{201B}" ); // single quotes + + // Chevrons (normal and "fullwidth" variants) + insert_pair!( "\u{00AB}\u{300A}", "\u{00BB}\u{300B}" ); // double chevrons, pointing away (<>) + insert_pair!( "\u{00BB}\u{300B}", "\u{00AB}\u{300A}" ); // double chevrons, pointing together (>>text<<) + insert_pair!( "\u{2039}\u{3008}", "\u{203A}\u{3009}" ); // single chevrons, pointing away () + insert_pair!( "\u{203A}\u{3009}", "\u{2039}\u{3008}" ); // single chevrons, pointing together (>text<) + + // Other + insert_pair!( "\u{300C}\u{300E}", "\u{300D}\u{300F}" ); // corner brackets (Japanese/Chinese) + + pairs + }; +} + +// very very simple quote matching +// quotes need to be at start/end of words, and are ignored if a closing quote is not present +// WTB POSIX quoting: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html +pub fn next_param(input: String, current_pos: usize) -> Option<(String, usize)> { + if input.len() == current_pos { + return None; + } + + let leading_whitespace_count = + input[..current_pos].len() - input[..current_pos].trim_start().len(); + let substr_to_match = input[current_pos + leading_whitespace_count..].to_string(); + println!("stuff: {input} {current_pos} {leading_whitespace_count}"); + println!("to match: {substr_to_match}"); + + // try matching end quote + if let Some(right) = QUOTE_PAIRS.get(&substr_to_match[0..1]) { + for possible_quote in right.chars() { + for (pos, _) in substr_to_match.match_indices(possible_quote) { + if substr_to_match.len() == pos + 1 + || substr_to_match + .chars() + .nth(pos + 1) + .unwrap() + .is_whitespace() + { + // return quoted string, without quotes + return Some(( + substr_to_match[1..pos - 1].to_string(), + current_pos + pos + 1, + )); + } + } + } + } + + // find next whitespace character + for (pos, char) in substr_to_match.clone().char_indices() { + if char.is_whitespace() { + return Some((substr_to_match[..pos].to_string(), current_pos + pos + 1)); + } + } + + // if we're here, we went to EOF and didn't match any whitespace + // so we return the whole string + Some((substr_to_match.clone(), current_pos + substr_to_match.len())) +} diff --git a/lib/commands/src/token.rs b/lib/commands/src/token.rs new file mode 100644 index 00000000..9d952a24 --- /dev/null +++ b/lib/commands/src/token.rs @@ -0,0 +1,84 @@ +#[derive(Debug, Clone, Eq, Hash, PartialEq)] +pub enum Token { + /// Token used to represent a finished command (i.e. no more parameters required) + // todo: this is likely not the right way to represent this + Empty, + + /// A bot-defined value ("member" in `pk;member MyName`) + Value(Vec), + /// A command defined by multiple values + // todo! + MultiValue(Vec>), + + FullString, + + /// Member reference (hid or member name) + MemberRef, + MemberPrivacyTarget, + + PrivacyLevel, + + // currently not included in command definitions + // todo: flags with values + Flag, +} + +pub enum TokenMatchResult { + NoMatch, + /// Token matched, optionally with a value. + Match(Option), +} + +// move this somewhere else +lazy_static::lazy_static!( + static ref MEMBER_PRIVACY_TARGETS: Vec = vec![ + "visibility".to_string(), + "name".to_string(), + "todo".to_string() + ]; +); + +impl Token { + pub fn try_match(&self, input: Option) -> TokenMatchResult { + // short circuit on empty things + if matches!(self, Self::Empty) && input.is_none() { + return TokenMatchResult::Match(None); + } else if input.is_none() { + return TokenMatchResult::NoMatch; + } + + let input = input.unwrap(); + + // try actually matching stuff + match self { + Self::Empty => return TokenMatchResult::NoMatch, + Self::Flag => unreachable!(), // matched upstream + Self::Value(values) => { + for v in values { + if input.trim() == v { + // c# bot currently needs subcommands provided as arguments + // todo!: remove this + return TokenMatchResult::Match(Some(v.clone())); + } + } + } + Self::MultiValue(_) => todo!(), + Self::FullString => return TokenMatchResult::Match(Some(input)), + Self::MemberRef => return TokenMatchResult::Match(Some(input)), + Self::MemberPrivacyTarget + if MEMBER_PRIVACY_TARGETS.contains(&input.trim().to_string()) => + { + return TokenMatchResult::Match(Some(input)) + } + Self::MemberPrivacyTarget => {} + Self::PrivacyLevel if input == "public" || input == "private" => { + return TokenMatchResult::Match(Some(input)) + } + Self::PrivacyLevel => {} + } + // note: must not add a _ case to the above match + // instead, for conditional matches, also add generic cases with no return + + return TokenMatchResult::NoMatch; + } +} diff --git a/lib/commands/uniffi.toml b/lib/commands/uniffi.toml new file mode 100644 index 00000000..86d3d6f1 --- /dev/null +++ b/lib/commands/uniffi.toml @@ -0,0 +1,2 @@ +[bindings.csharp] +cdylib_name = "commands" From fd7d3e6a3a75f943c812bb3a319b0f245af02362 Mon Sep 17 00:00:00 2001 From: alyssa Date: Fri, 13 Sep 2024 18:34:32 +0900 Subject: [PATCH 2/9] use quote! for generating code instead --- lib/command_system_macros/Cargo.toml | 4 ++ lib/command_system_macros/src/lib.rs | 82 ++++++++++++++++------------ 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/lib/command_system_macros/Cargo.toml b/lib/command_system_macros/Cargo.toml index cf660792..269371c6 100644 --- a/lib/command_system_macros/Cargo.toml +++ b/lib/command_system_macros/Cargo.toml @@ -5,3 +5,7 @@ edition = "2021" [lib] proc-macro = true + +[dependencies] +quote = "1.0" +proc-macro2 = "1.0" diff --git a/lib/command_system_macros/src/lib.rs b/lib/command_system_macros/src/lib.rs index 854844c6..6a8190ee 100644 --- a/lib/command_system_macros/src/lib.rs +++ b/lib/command_system_macros/src/lib.rs @@ -1,19 +1,28 @@ use proc_macro::{Delimiter, TokenStream, TokenTree}; +use proc_macro2::{Ident, Literal, Span}; +use quote::quote; -fn make_command(tokens: Vec, help: String, cb: String) -> String { - let tokens = tokens - .iter() - .map(|v| format!("Token::{v}")) - .collect::>() - .join(","); - format!( - r#"Command {{ tokens: vec![{tokens}], help: {help}.to_string(), cb: "{cb}".to_string() }}"# - ) +fn make_command( + tokens: Vec, + help: String, + cb: String, +) -> proc_macro2::TokenStream { + let help = Literal::string(&help); + let cb = Literal::string(&cb); + + quote! { + Command { tokens: vec![#(#tokens),*], help: #help.to_string(), cb: #cb.to_string() } + } } -fn command_from_stream(stream: TokenStream) -> String { +// horrible, but the best way i could find to do this +fn token_to_string(i: String) -> String { + i.to_string()[1..i.to_string().len() - 1].to_string() +} + +fn command_from_stream(stream: TokenStream) -> proc_macro2::TokenStream { let mut part = 0; - let mut found_tokens: Vec = Vec::new(); + let mut found_tokens: Vec = Vec::new(); let mut found_cb: Option = None; let mut found_help: Option = None; @@ -25,9 +34,11 @@ fn command_from_stream(stream: TokenStream) -> String { None if part == 2 && found_help.is_some() => break 'a, Some(TokenTree::Ident(ident)) if part == 0 => { found_tokens.push(if is_token_lit { - format!("{ident}") + let ident = Ident::new(ident.to_string().as_str(), Span::call_site()); + quote! { Token::#ident }.into() } else { - format!("Value(vec![\"{ident}\".to_string()])") + let ident = Literal::string(format!("{ident}").as_str()); + quote! { Token::Value(vec![#ident.to_string() ]) } }); // reset this is_token_lit = false; @@ -42,7 +53,9 @@ fn command_from_stream(stream: TokenStream) -> String { part += 1 } Some(TokenTree::Ident(ident)) if part == 1 => found_cb = Some(format!("{ident}")), - Some(TokenTree::Literal(lit)) if part == 2 => found_help = Some(format!("{lit}")), + Some(TokenTree::Literal(lit)) if part == 2 => { + found_help = Some(token_to_string(lit.to_string())) + } _ => panic!("invalid command definition: {stream}"), } } @@ -51,7 +64,7 @@ fn command_from_stream(stream: TokenStream) -> String { #[proc_macro] pub fn commands(stream: TokenStream) -> TokenStream { - let mut commands: Vec = Vec::new(); + let mut commands: Vec = Vec::new(); let mut top_level_tokens = stream.into_iter(); 'a: loop { @@ -77,33 +90,30 @@ pub fn commands(stream: TokenStream) -> TokenStream { let command_registrations = commands .iter() - .map(|v| format!("tree.register_command({v});")) - .collect::>() - .join("\n"); + .map(|v| -> proc_macro2::TokenStream { quote! { tree.register_command(#v); }.into() }) + .collect::(); - let res = format!( - r#" -lazy_static::lazy_static! {{ - static ref COMMAND_TREE: TreeBranch = {{ - let mut tree = TreeBranch {{ - current_command_key: None, - possible_tokens: vec![], - branches: HashMap::new(), - }}; + let res = quote! { + lazy_static::lazy_static! { + static ref COMMAND_TREE: TreeBranch = { + let mut tree = TreeBranch { + current_command_key: None, + possible_tokens: vec![], + branches: HashMap::new(), + }; - {command_registrations} + #command_registrations - tree.sort_tokens(); + tree.sort_tokens(); - // println!("{{tree:#?}}"); + // println!("{{tree:#?}}"); - tree - }}; -}} - "# - ); + tree + }; + } + }; // panic!("{res}"); - res.parse().unwrap() + res.into() } From c99b59673a369b1375d60188d0a8be9c1091b40e Mon Sep 17 00:00:00 2001 From: Iris System Date: Fri, 13 Sep 2024 22:17:11 +1200 Subject: [PATCH 3/9] use proc_macro2 as much as possible --- lib/command_system_macros/src/lib.rs | 43 ++++++++++++---------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/lib/command_system_macros/src/lib.rs b/lib/command_system_macros/src/lib.rs index 6a8190ee..034f377a 100644 --- a/lib/command_system_macros/src/lib.rs +++ b/lib/command_system_macros/src/lib.rs @@ -1,30 +1,21 @@ -use proc_macro::{Delimiter, TokenStream, TokenTree}; -use proc_macro2::{Ident, Literal, Span}; +use proc_macro2::{Delimiter, TokenStream, TokenTree, Ident, Literal, Span}; use quote::quote; fn make_command( - tokens: Vec, - help: String, - cb: String, -) -> proc_macro2::TokenStream { - let help = Literal::string(&help); - let cb = Literal::string(&cb); - + tokens: Vec, + help: Literal, + cb: Literal, +) -> TokenStream { quote! { Command { tokens: vec![#(#tokens),*], help: #help.to_string(), cb: #cb.to_string() } } } -// horrible, but the best way i could find to do this -fn token_to_string(i: String) -> String { - i.to_string()[1..i.to_string().len() - 1].to_string() -} - -fn command_from_stream(stream: TokenStream) -> proc_macro2::TokenStream { +fn command_from_stream(stream: TokenStream) -> TokenStream { let mut part = 0; - let mut found_tokens: Vec = Vec::new(); - let mut found_cb: Option = None; - let mut found_help: Option = None; + let mut found_tokens: Vec = Vec::new(); + let mut found_cb: Option = None; + let mut found_help: Option = None; let mut is_token_lit = false; let mut tokens = stream.clone().into_iter(); @@ -34,11 +25,10 @@ fn command_from_stream(stream: TokenStream) -> proc_macro2::TokenStream { None if part == 2 && found_help.is_some() => break 'a, Some(TokenTree::Ident(ident)) if part == 0 => { found_tokens.push(if is_token_lit { - let ident = Ident::new(ident.to_string().as_str(), Span::call_site()); quote! { Token::#ident }.into() } else { - let ident = Literal::string(format!("{ident}").as_str()); - quote! { Token::Value(vec![#ident.to_string() ]) } + let lit = Literal::string(&format!("{ident}")); + quote! { Token::Value(vec![#lit.to_string() ]) } }); // reset this is_token_lit = false; @@ -52,9 +42,11 @@ fn command_from_stream(stream: TokenStream) -> proc_macro2::TokenStream { { part += 1 } - Some(TokenTree::Ident(ident)) if part == 1 => found_cb = Some(format!("{ident}")), + Some(TokenTree::Ident(ident)) if part == 1 => { + found_cb = Some(Literal::string(&format!("{ident}"))) + } Some(TokenTree::Literal(lit)) if part == 2 => { - found_help = Some(token_to_string(lit.to_string())) + found_help = Some(lit) } _ => panic!("invalid command definition: {stream}"), } @@ -63,8 +55,9 @@ fn command_from_stream(stream: TokenStream) -> proc_macro2::TokenStream { } #[proc_macro] -pub fn commands(stream: TokenStream) -> TokenStream { - let mut commands: Vec = Vec::new(); +pub fn commands(stream: proc_macro::TokenStream) -> proc_macro::TokenStream { + let stream: TokenStream = stream.into(); + let mut commands: Vec = Vec::new(); let mut top_level_tokens = stream.into_iter(); 'a: loop { From fce23c2b90f892780ec9197595f2d04976c40bbe Mon Sep 17 00:00:00 2001 From: Iris System Date: Fri, 13 Sep 2024 22:17:42 +1200 Subject: [PATCH 4/9] force resolver="2" for cargo workspace, update lockfile --- Cargo.lock | 4 ++++ Cargo.toml | 1 + 2 files changed, 5 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index abc1e061..69322627 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -472,6 +472,10 @@ dependencies = [ [[package]] name = "command_system_macros" version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", +] [[package]] name = "commands" diff --git a/Cargo.toml b/Cargo.toml index 3866b321..0dc72064 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "./lib/libpk", "./lib/commands", From 737d6d3216b57168d0c4c3d092e8d52efad4275a Mon Sep 17 00:00:00 2001 From: Iris System Date: Fri, 13 Sep 2024 23:58:56 +1200 Subject: [PATCH 5/9] make the proc macro DSL parser far more readable --- Cargo.lock | 1 + lib/command_system_macros/Cargo.toml | 1 + lib/command_system_macros/src/lib.rs | 137 +++++++++++++++++---------- 3 files changed, 90 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 69322627..495b0dd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -475,6 +475,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", + "syn 2.0.77", ] [[package]] diff --git a/lib/command_system_macros/Cargo.toml b/lib/command_system_macros/Cargo.toml index 269371c6..7d2aa1b0 100644 --- a/lib/command_system_macros/Cargo.toml +++ b/lib/command_system_macros/Cargo.toml @@ -9,3 +9,4 @@ proc-macro = true [dependencies] quote = "1.0" proc-macro2 = "1.0" +syn = "2.0" diff --git a/lib/command_system_macros/src/lib.rs b/lib/command_system_macros/src/lib.rs index 034f377a..1f863ec3 100644 --- a/lib/command_system_macros/src/lib.rs +++ b/lib/command_system_macros/src/lib.rs @@ -1,57 +1,95 @@ -use proc_macro2::{Delimiter, TokenStream, TokenTree, Ident, Literal, Span}; -use quote::quote; +use proc_macro2::{Delimiter, TokenStream, TokenTree, Literal, Span}; +use syn::parse::{Parse, ParseStream, Result as ParseResult}; +use syn::{parse_macro_input, Token, Ident}; +use quote::{quote, quote_spanned}; -fn make_command( - tokens: Vec, - help: Literal, - cb: Literal, -) -> TokenStream { - quote! { - Command { tokens: vec![#(#tokens),*], help: #help.to_string(), cb: #cb.to_string() } +enum CommandToken { + /// "typed argument" being a member of the `Token` enum in the + /// command parser crate. + /// + /// prefixed with `@` in the command macro. + TypedArgument(Ident, Span), + + /// interpreted as a literal string in the command input. + /// + /// no prefix in the command macro. + Literal(Literal, Span), +} + +impl Parse for CommandToken { + fn parse(input: ParseStream) -> ParseResult { + let lookahead = input.lookahead1(); + if lookahead.peek(Token![@]) { + // typed argument + input.parse::()?; + let ident = input.parse::()?; + Ok(Self::TypedArgument(ident.clone(), ident.span())) + } else if lookahead.peek(Ident) { + // literal string + let ident = input.parse::()?; + let lit = Literal::string(&format!("{ident}")); + Ok(Self::Literal(lit, ident.span())) + } else { + Err(input.error("expected a command token")) + } } } -fn command_from_stream(stream: TokenStream) -> TokenStream { - let mut part = 0; - let mut found_tokens: Vec = Vec::new(); - let mut found_cb: Option = None; - let mut found_help: Option = None; +impl Into for CommandToken { + fn into(self) -> TokenStream { + match self { + Self::TypedArgument(ident, span) => quote_spanned! {span=> + Token::#ident + }, - let mut is_token_lit = false; - let mut tokens = stream.clone().into_iter(); - 'a: loop { - let cur_token = tokens.next(); - match cur_token { - None if part == 2 && found_help.is_some() => break 'a, - Some(TokenTree::Ident(ident)) if part == 0 => { - found_tokens.push(if is_token_lit { - quote! { Token::#ident }.into() - } else { - let lit = Literal::string(&format!("{ident}")); - quote! { Token::Value(vec![#lit.to_string() ]) } - }); - // reset this - is_token_lit = false; + Self::Literal(lit, span) => quote_spanned! {span=> + Token::Value(vec![ #lit.to_string(), ]) + }, + }.into() + } +} + +struct Command { + tokens: Vec, + help: Literal, + cb: Literal, +} + +impl Parse for Command { + fn parse(input: ParseStream) -> ParseResult { + let mut tokens = Vec::::new(); + loop { + if input.peek(Token![,]) { + break; } - Some(TokenTree::Punct(punct)) if part == 0 && format!("{punct}") == "@" => { - is_token_lit = true - } - Some(TokenTree::Punct(punct)) - if ((part == 0 && found_tokens.len() > 0) || (part == 1 && found_cb.is_some())) - && format!("{punct}") == "," => - { - part += 1 - } - Some(TokenTree::Ident(ident)) if part == 1 => { - found_cb = Some(Literal::string(&format!("{ident}"))) - } - Some(TokenTree::Literal(lit)) if part == 2 => { - found_help = Some(lit) - } - _ => panic!("invalid command definition: {stream}"), + + tokens.push(input.parse::()?); + } + input.parse::()?; + + let cb_ident = input.parse::()?; + let cb = Literal::string(&format!("{cb_ident}")); + input.parse::()?; + + let help = input.parse::()?; + + Ok(Self { + tokens, + cb, + help, + }) + } +} + +impl Into for Command { + fn into(self) -> TokenStream { + let Self { tokens, help, cb } = self; + let tokens = tokens.into_iter().map(Into::into).collect::>(); + + quote! { + Command { tokens: vec![#(#tokens),*], help: #help.to_string(), cb: #cb.to_string() } } } - make_command(found_tokens, found_help.unwrap(), found_cb.unwrap()) } #[proc_macro] @@ -70,7 +108,8 @@ pub fn commands(stream: proc_macro::TokenStream) -> proc_macro::TokenStream { // match top_level_tokens.next() { Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Parenthesis => { - commands.push(command_from_stream(group.stream())); + let group_stream: proc_macro::TokenStream = group.stream().into(); + commands.push(parse_macro_input!(group_stream as Command).into()); } _ => panic!("contents of commands! macro is invalid"), } @@ -83,8 +122,8 @@ pub fn commands(stream: proc_macro::TokenStream) -> proc_macro::TokenStream { let command_registrations = commands .iter() - .map(|v| -> proc_macro2::TokenStream { quote! { tree.register_command(#v); }.into() }) - .collect::(); + .map(|v| -> TokenStream { quote! { tree.register_command(#v); }.into() }) + .collect::(); let res = quote! { lazy_static::lazy_static! { From b6eec3784dfe43c2cddef0c2dcff72c0b39e6d90 Mon Sep 17 00:00:00 2001 From: libglfw Date: Sat, 2 Nov 2024 14:55:06 -0700 Subject: [PATCH 6/9] remove command_system_macros --- lib/command_system_macros/Cargo.toml | 12 --- lib/command_system_macros/src/lib.rs | 151 --------------------------- lib/commands/Cargo.toml | 1 - lib/commands/src/lib.rs | 104 +++++++++++++++--- lib/commands/src/string.rs | 1 + 5 files changed, 93 insertions(+), 176 deletions(-) delete mode 100644 lib/command_system_macros/Cargo.toml delete mode 100644 lib/command_system_macros/src/lib.rs diff --git a/lib/command_system_macros/Cargo.toml b/lib/command_system_macros/Cargo.toml deleted file mode 100644 index 7d2aa1b0..00000000 --- a/lib/command_system_macros/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "command_system_macros" -version = "0.1.0" -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -quote = "1.0" -proc-macro2 = "1.0" -syn = "2.0" diff --git a/lib/command_system_macros/src/lib.rs b/lib/command_system_macros/src/lib.rs deleted file mode 100644 index 1f863ec3..00000000 --- a/lib/command_system_macros/src/lib.rs +++ /dev/null @@ -1,151 +0,0 @@ -use proc_macro2::{Delimiter, TokenStream, TokenTree, Literal, Span}; -use syn::parse::{Parse, ParseStream, Result as ParseResult}; -use syn::{parse_macro_input, Token, Ident}; -use quote::{quote, quote_spanned}; - -enum CommandToken { - /// "typed argument" being a member of the `Token` enum in the - /// command parser crate. - /// - /// prefixed with `@` in the command macro. - TypedArgument(Ident, Span), - - /// interpreted as a literal string in the command input. - /// - /// no prefix in the command macro. - Literal(Literal, Span), -} - -impl Parse for CommandToken { - fn parse(input: ParseStream) -> ParseResult { - let lookahead = input.lookahead1(); - if lookahead.peek(Token![@]) { - // typed argument - input.parse::()?; - let ident = input.parse::()?; - Ok(Self::TypedArgument(ident.clone(), ident.span())) - } else if lookahead.peek(Ident) { - // literal string - let ident = input.parse::()?; - let lit = Literal::string(&format!("{ident}")); - Ok(Self::Literal(lit, ident.span())) - } else { - Err(input.error("expected a command token")) - } - } -} - -impl Into for CommandToken { - fn into(self) -> TokenStream { - match self { - Self::TypedArgument(ident, span) => quote_spanned! {span=> - Token::#ident - }, - - Self::Literal(lit, span) => quote_spanned! {span=> - Token::Value(vec![ #lit.to_string(), ]) - }, - }.into() - } -} - -struct Command { - tokens: Vec, - help: Literal, - cb: Literal, -} - -impl Parse for Command { - fn parse(input: ParseStream) -> ParseResult { - let mut tokens = Vec::::new(); - loop { - if input.peek(Token![,]) { - break; - } - - tokens.push(input.parse::()?); - } - input.parse::()?; - - let cb_ident = input.parse::()?; - let cb = Literal::string(&format!("{cb_ident}")); - input.parse::()?; - - let help = input.parse::()?; - - Ok(Self { - tokens, - cb, - help, - }) - } -} - -impl Into for Command { - fn into(self) -> TokenStream { - let Self { tokens, help, cb } = self; - let tokens = tokens.into_iter().map(Into::into).collect::>(); - - quote! { - Command { tokens: vec![#(#tokens),*], help: #help.to_string(), cb: #cb.to_string() } - } - } -} - -#[proc_macro] -pub fn commands(stream: proc_macro::TokenStream) -> proc_macro::TokenStream { - let stream: TokenStream = stream.into(); - let mut commands: Vec = Vec::new(); - - let mut top_level_tokens = stream.into_iter(); - 'a: loop { - // "command" - match top_level_tokens.next() { - Some(TokenTree::Ident(ident)) if format!("{ident}") == "command" => {} - None => break 'a, - _ => panic!("contents of commands! macro is invalid"), - } - // - match top_level_tokens.next() { - Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Parenthesis => { - let group_stream: proc_macro::TokenStream = group.stream().into(); - commands.push(parse_macro_input!(group_stream as Command).into()); - } - _ => panic!("contents of commands! macro is invalid"), - } - // ; - match top_level_tokens.next() { - Some(TokenTree::Punct(punct)) if format!("{punct}") == ";" => {} - _ => panic!("contents of commands! macro is invalid"), - } - } - - let command_registrations = commands - .iter() - .map(|v| -> TokenStream { quote! { tree.register_command(#v); }.into() }) - .collect::(); - - let res = quote! { - lazy_static::lazy_static! { - static ref COMMAND_TREE: TreeBranch = { - let mut tree = TreeBranch { - current_command_key: None, - possible_tokens: vec![], - branches: HashMap::new(), - }; - - #command_registrations - - tree.sort_tokens(); - - // println!("{{tree:#?}}"); - - tree - }; - } - }; - - // panic!("{res}"); - - res.into() -} diff --git a/lib/commands/Cargo.toml b/lib/commands/Cargo.toml index 1d1ac480..efff1dea 100644 --- a/lib/commands/Cargo.toml +++ b/lib/commands/Cargo.toml @@ -8,7 +8,6 @@ crate-type = ["cdylib"] [dependencies] lazy_static = { workspace = true } -command_system_macros = { path = "../command_system_macros" } uniffi = { version = "0.25" } diff --git a/lib/commands/src/lib.rs b/lib/commands/src/lib.rs index 0217dec7..6b787403 100644 --- a/lib/commands/src/lib.rs +++ b/lib/commands/src/lib.rs @@ -9,8 +9,6 @@ mod string; mod token; use token::*; -use command_system_macros::commands; - // todo!: move all this stuff into a different file // lib.rs should just have exported symbols and command definitions @@ -69,23 +67,105 @@ impl TreeBranch { } } +#[derive(Clone)] struct Command { tokens: Vec, help: String, cb: String, } -// todo: aliases -// todo: categories -commands! { - command(help, help, "Shows the help command"); +fn command(tokens: &[&Token], help: &str, cb: &str) -> Command { + Command { + tokens: tokens.iter().map(|&x| x.clone()).collect(), + help: help.to_string(), + cb: cb.to_string(), + } +} - command(member new, member_new, "Creates a new system member"); - command(member @MemberRef, member_show, "Shows information about a member"); - command(member @MemberRef description, member_desc_show, "Shows a member's description"); - command(member @MemberRef description @FullString, member_desc_update, "Changes a member's description"); - command(member @MemberRef privacy, member_privacy_show, "Displays a member's current privacy settings"); - command(member @MemberRef privacy @MemberPrivacyTarget @PrivacyLevel, member_privacy_update, "Changes a member's privacy settings"); +mod commands { + use super::Token; + + use super::command; + use super::Token::*; + + fn cmd(value: &str) -> Token { + Token::Value(vec![value.to_string()]) + } + + pub fn cmd_with_alias(value: &[&str]) -> Token { + Token::Value(value.iter().map(|x| x.to_string()).collect()) + } + + // todo: this needs to have less ampersands -alyssa + pub fn happy() -> Vec { + let system = &cmd_with_alias(&["system", "s"]); + let member = &cmd_with_alias(&["member", "m"]); + let description = &cmd_with_alias(&["description", "desc"]); + let privacy = &cmd_with_alias(&["privacy", "priv"]); + vec![ + command(&[&cmd("help")], "help", "Shows the help command"), + command( + &[system], + "system_show", + "Shows information about your system", + ), + command(&[system, &cmd("new")], "system_new", "Creates a new system"), + command( + &[member, &cmd_with_alias(&["new", "n"])], + "member_new", + "Creates a new system member", + ), + command( + &[member, &MemberRef], + "member_show", + "Shows information about a member", + ), + command( + &[member, &MemberRef, description], + "member_desc_show", + "Shows a member's description", + ), + command( + &[member, &MemberRef, description, &FullString], + "member_desc_update", + "Changes a member's description", + ), + command( + &[member, &MemberRef, privacy], + "member_privacy_show", + "Displays a member's current privacy settings", + ), + command( + &[ + member, + &MemberRef, + privacy, + &MemberPrivacyTarget, + &PrivacyLevel, + ], + "member_privacy_update", + "Changes a member's privacy settings", + ), + ] + } +} + +lazy_static::lazy_static! { + static ref COMMAND_TREE: TreeBranch = { + let mut tree = TreeBranch { + current_command_key: None, + possible_tokens: vec![], + branches: HashMap::new(), + }; + + commands::happy().iter().for_each(|x| tree.register_command(x.clone())); + + tree.sort_tokens(); + + // println!("{{tree:#?}}"); + + tree + }; } pub enum CommandResult { diff --git a/lib/commands/src/string.rs b/lib/commands/src/string.rs index bc65c8a0..0ea7659a 100644 --- a/lib/commands/src/string.rs +++ b/lib/commands/src/string.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; lazy_static::lazy_static! { // Dictionary of (left, right) quote pairs // Each char in the string is an individual quote, multi-char strings imply "one of the following chars" + // Certain languages can have quote patterns that have a different character for open and close pub static ref QUOTE_PAIRS: HashMap = { let mut pairs = HashMap::new(); From 26f855b7b9a111fed3f8b52577c4282058f9b545 Mon Sep 17 00:00:00 2001 From: libglfw Date: Sat, 2 Nov 2024 14:55:19 -0700 Subject: [PATCH 7/9] improve nix devshell --- flake.lock | 269 ++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 46 ++++++++ rust-toolchain.toml | 3 + 3 files changed, 318 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 rust-toolchain.toml diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..1ef62906 --- /dev/null +++ b/flake.lock @@ -0,0 +1,269 @@ +{ + "nodes": { + "crane": { + "flake": false, + "locked": { + "lastModified": 1727316705, + "narHash": "sha256-/mumx8AQ5xFuCJqxCIOFCHTVlxHkMT21idpbgbm/TIE=", + "owner": "ipetkov", + "repo": "crane", + "rev": "5b03654ce046b5167e7b0bccbd8244cb56c16f0e", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "ref": "v0.19.0", + "repo": "crane", + "type": "github" + } + }, + "dream2nix": { + "inputs": { + "nixpkgs": [ + "nci", + "nixpkgs" + ], + "purescript-overlay": "purescript-overlay", + "pyproject-nix": "pyproject-nix" + }, + "locked": { + "lastModified": 1728585693, + "narHash": "sha256-rhx5SYpIkPu7d+rjF9FGGBVxS0BwAEkmYIsJg2a3E20=", + "owner": "nix-community", + "repo": "dream2nix", + "rev": "c6935471f7e1a9e190aaa9ac9823dca34e00d92a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "dream2nix", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "mk-naked-shell": { + "flake": false, + "locked": { + "lastModified": 1681286841, + "narHash": "sha256-3XlJrwlR0nBiREnuogoa5i1b4+w/XPe0z8bbrJASw0g=", + "owner": "yusdacra", + "repo": "mk-naked-shell", + "rev": "7612f828dd6f22b7fb332cc69440e839d7ffe6bd", + "type": "github" + }, + "original": { + "owner": "yusdacra", + "repo": "mk-naked-shell", + "type": "github" + } + }, + "nci": { + "inputs": { + "crane": "crane", + "dream2nix": "dream2nix", + "mk-naked-shell": "mk-naked-shell", + "nixpkgs": [ + "nixpkgs" + ], + "parts": "parts", + "rust-overlay": "rust-overlay", + "treefmt": "treefmt" + }, + "locked": { + "lastModified": 1729836952, + "narHash": "sha256-1XE0s+JiwzoHaAul4wqeGjo28IxF81nZOWuubfXc1vo=", + "owner": "yusdacra", + "repo": "nix-cargo-integration", + "rev": "712068c3707990320ee0b225bd82ecd8687dca96", + "type": "github" + }, + "original": { + "owner": "yusdacra", + "repo": "nix-cargo-integration", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1729665710, + "narHash": "sha256-AlcmCXJZPIlO5dmFzV3V2XF6x/OpNWUV8Y/FMPGd8Z4=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "2768c7d042a37de65bb1b5b3268fc987e534c49d", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "parts": { + "inputs": { + "nixpkgs-lib": [ + "nci", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1727826117, + "narHash": "sha256-K5ZLCyfO/Zj9mPFldf3iwS6oZStJcU4tSpiXTMYaaL0=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "3d04084d54bedc3d6b8b736c70ef449225c361b1", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "parts_2": { + "inputs": { + "nixpkgs-lib": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1727826117, + "narHash": "sha256-K5ZLCyfO/Zj9mPFldf3iwS6oZStJcU4tSpiXTMYaaL0=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "3d04084d54bedc3d6b8b736c70ef449225c361b1", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "purescript-overlay": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": [ + "nci", + "dream2nix", + "nixpkgs" + ], + "slimlock": "slimlock" + }, + "locked": { + "lastModified": 1724504251, + "narHash": "sha256-TIw+sac0NX0FeAneud+sQZT+ql1G/WEb7/Vb436rUXM=", + "owner": "thomashoneyman", + "repo": "purescript-overlay", + "rev": "988b09676c2a0e6a46dfa3589aa6763c90476b8a", + "type": "github" + }, + "original": { + "owner": "thomashoneyman", + "repo": "purescript-overlay", + "type": "github" + } + }, + "pyproject-nix": { + "flake": false, + "locked": { + "lastModified": 1702448246, + "narHash": "sha256-hFg5s/hoJFv7tDpiGvEvXP0UfFvFEDgTdyHIjDVHu1I=", + "owner": "davhau", + "repo": "pyproject.nix", + "rev": "5a06a2697b228c04dd2f35659b4b659ca74f7aeb", + "type": "github" + }, + "original": { + "owner": "davhau", + "ref": "dream2nix", + "repo": "pyproject.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "nci": "nci", + "nixpkgs": "nixpkgs", + "parts": "parts_2" + } + }, + "rust-overlay": { + "flake": false, + "locked": { + "lastModified": 1729823394, + "narHash": "sha256-RiinJqorqSLKh1oSpiMHnBe6nQdJzE45lX6fSnAuDnI=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "7e52e80f5faa374ad4c607d62c6d362589cb523f", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "slimlock": { + "inputs": { + "nixpkgs": [ + "nci", + "dream2nix", + "purescript-overlay", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1688756706, + "narHash": "sha256-xzkkMv3neJJJ89zo3o2ojp7nFeaZc2G0fYwNXNJRFlo=", + "owner": "thomashoneyman", + "repo": "slimlock", + "rev": "cf72723f59e2340d24881fd7bf61cb113b4c407c", + "type": "github" + }, + "original": { + "owner": "thomashoneyman", + "repo": "slimlock", + "type": "github" + } + }, + "treefmt": { + "inputs": { + "nixpkgs": [ + "nci", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1729613947, + "narHash": "sha256-XGOvuIPW1XRfPgHtGYXd5MAmJzZtOuwlfKDgxX5KT3s=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "aac86347fb5063960eccb19493e0cadcdb4205ca", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..c0da6660 --- /dev/null +++ b/flake.nix @@ -0,0 +1,46 @@ +{ + inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + inputs.nci.url = "github:yusdacra/nix-cargo-integration"; + inputs.nci.inputs.nixpkgs.follows = "nixpkgs"; + inputs.parts.url = "github:hercules-ci/flake-parts"; + inputs.parts.inputs.nixpkgs-lib.follows = "nixpkgs"; + + outputs = inputs @ { + parts, + nci, + ... + }: + parts.lib.mkFlake {inherit inputs;} { + systems = ["x86_64-linux"]; + imports = [nci.flakeModule]; + perSystem = { + config, + pkgs, + ... + }: let + rustOutputs = config.nci.outputs; + rustDeps = with pkgs; [rust-analyzer]; + webDeps = with pkgs; [yarn nodejs]; + csDeps = with pkgs; [gcc protobuf dotnet-sdk_6 go]; + in { + nci.toolchainConfig = ./rust-toolchain.toml; + nci.projects."pluralkit" = { + path = ./.; + export = true; + }; + # configure crates + nci.crates = { + # see for usage: https://github.com/yusdacra/nix-cargo-integration/blob/master/examples/simple-workspace/crates.nix + }; + + devShells.default = rustOutputs."pluralkit".devShell.overrideAttrs (old: { + nativeBuildInputs = old.nativeBuildInputs ++ webDeps ++ csDeps ++ rustDeps; + }); + devShells.web = pkgs.mkShell {nativeBuildInputs = webDeps;}; + devShells.rust = rustOutputs."pluralkit".devShell.overrideAttrs (old: { nativeBuildInputs = old.nativeBuildInputs ++ rustDeps; }); + devShells.cs= pkgs.mkShell { + nativeBuildInputs = csDeps; + }; + }; + }; +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..2792be0d --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2024-08-20" + From 3bf14256d82df26123b983586d40c7092ae05ecf Mon Sep 17 00:00:00 2001 From: libglfw Date: Sat, 2 Nov 2024 15:08:43 -0700 Subject: [PATCH 8/9] update cargo lock --- Cargo.lock | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 495b0dd9..6e060b33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -469,20 +469,10 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "command_system_macros" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - [[package]] name = "commands" version = "0.1.0" dependencies = [ - "command_system_macros", "lazy_static", "uniffi", ] From 4d4138c4b14b6002c748a7290ebec9dce13fe97a Mon Sep 17 00:00:00 2001 From: libglfw Date: Sat, 2 Nov 2024 15:14:53 -0700 Subject: [PATCH 9/9] fix Cargo.lock --- Cargo.lock | 192 ++++++++++++++++++++++++++++------------------------- 1 file changed, 103 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e060b33..12e7ae2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", @@ -135,7 +135,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.77", + "syn 2.0.66", ] [[package]] @@ -161,7 +161,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.66", ] [[package]] @@ -399,9 +399,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bytes-utils" @@ -479,9 +479,9 @@ dependencies = [ [[package]] name = "config" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d379af7f68bfc21714c6c7dea883544201741d2ce8274bb12fa54f89507f52a7" +checksum = "23738e11972c7643e4ec947840fc463b6a571afcd3e735bdfce7d03c7a784aca" dependencies = [ "async-trait", "json5", @@ -671,7 +671,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.66", ] [[package]] @@ -872,7 +872,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.66", ] [[package]] @@ -965,7 +965,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.8", ] [[package]] @@ -1230,9 +1230,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", @@ -1311,9 +1311,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", @@ -1390,9 +1390,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libm" @@ -1499,9 +1499,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" @@ -1518,9 +1518,9 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b9b8653cec6897f73b519a43fba5ee3d50f62fe9af80b428accdcc093b4a849" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.8", "metrics-macros", - "portable-atomic", + "portable-atomic 0.3.20", ] [[package]] @@ -1530,12 +1530,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8603921e1f54ef386189335f288441af761e0fc61bcb552168d9cedfe63ebc70" dependencies = [ "hyper 0.14.24", - "indexmap 1.9.2", + "indexmap 1.9.3", "ipnet", "metrics", "metrics-util", "parking_lot 0.12.1", - "portable-atomic", + "portable-atomic 0.3.20", "quanta", "thiserror", "tokio", @@ -1565,7 +1565,7 @@ dependencies = [ "metrics", "num_cpus", "parking_lot 0.12.1", - "portable-atomic", + "portable-atomic 0.3.20", "quanta", "sketches-ddsketch", ] @@ -1944,9 +1944,18 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "portable-atomic" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" +checksum = "e30165d31df606f5726b090ec7592c308a0eaf61721ff64c9a3018e344a8753e" +dependencies = [ + "portable-atomic 1.8.0", +] + +[[package]] +name = "portable-atomic" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce" [[package]] name = "ppv-lite86" @@ -1971,7 +1980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.66", ] [[package]] @@ -2010,7 +2019,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.77", + "syn 2.0.66", "tempfile", ] @@ -2024,7 +2033,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.66", ] [[package]] @@ -2060,9 +2069,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quinn" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "pin-project-lite", @@ -2078,9 +2087,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", @@ -2095,15 +2104,15 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ "libc", "once_cell", "socket2 0.5.7", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2198,14 +2207,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.3.7", + "regex-syntax 0.7.5", ] [[package]] @@ -2219,13 +2228,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.7.5", ] [[package]] @@ -2236,15 +2245,15 @@ checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" -version = "0.12.7" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", @@ -2379,9 +2388,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" dependencies = [ "once_cell", "ring", @@ -2393,9 +2402,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" dependencies = [ "base64 0.22.1", "rustls-pki-types", @@ -2403,15 +2412,15 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ "ring", "rustls-pki-types", @@ -2453,7 +2462,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.66", ] [[package]] @@ -2482,7 +2491,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.66", ] [[package]] @@ -2543,9 +2552,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -2896,9 +2905,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -2943,22 +2952,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.66", ] [[package]] @@ -3011,7 +3020,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.66", ] [[package]] @@ -3126,11 +3135,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -3139,20 +3147,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.66", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -3220,12 +3228,9 @@ checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" @@ -3319,7 +3324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55137c122f712d9330fd985d66fa61bdc381752e89c35708c13ce63049a3002c" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.66", ] [[package]] @@ -3351,7 +3356,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.77", + "syn 2.0.66", "toml", "uniffi_build", "uniffi_meta", @@ -3484,7 +3489,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -3518,7 +3523,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3531,9 +3536,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -3541,9 +3546,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -3679,6 +3684,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.42.1" @@ -3883,7 +3897,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.66", ] [[package]]