diff --git a/Cargo.lock b/Cargo.lock index 138b182..f61e557 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,7 +26,7 @@ dependencies = [ "http-signature-normalization-reqwest", "httpdate", "hyper", - "itertools", + "itertools 0.12.0", "moka", "once_cell", "openssl", @@ -108,6 +108,17 @@ dependencies = [ "event-listener", ] +[[package]] +name = "async-recursion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "async-trait" version = "0.1.74" @@ -119,6 +130,34 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "attribute-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c94f43ede6f25dab1dea046bff84d85dea61bd49aba7a9011ad66c0d449077b" +dependencies = [ + "attribute-derive-macro", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "attribute-derive-macro" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b409e2b2d2dc206d2c0ad3575a93f001ae21a1593e2d0c69b69c308e63f3b422" +dependencies = [ + "collection_literals", + "interpolator", + "manyhow", + "proc-macro-utils", + "proc-macro2", + "quote", + "quote-use", + "syn 2.0.39", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -343,6 +382,33 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cipher" version = "0.4.4" @@ -353,6 +419,75 @@ dependencies = [ "inout", ] +[[package]] +name = "collection_literals" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271" + +[[package]] +name = "config" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23738e11972c7643e4ec947840fc463b6a571afcd3e735bdfce7d03c7a784aca" +dependencies = [ + "async-trait", + "lazy_static", + "nom", + "pathdiff", + "serde", + "toml 0.5.11", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "const_format" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -464,6 +599,17 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive-where" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "derive_builder" version = "0.12.0" @@ -578,6 +724,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "drain_filter_polyfill" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" + [[package]] name = "dyn-clone" version = "1.0.16" @@ -699,6 +851,18 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "frontend" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook", + "console_log", + "leptos", + "log", + "reqwest", + "serde", +] + [[package]] name = "futures" version = "0.3.29" @@ -823,6 +987,39 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "gloo-net" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-utils" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "h2" version = "0.3.21" @@ -842,6 +1039,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + [[package]] name = "hashbrown" version = "0.12.3" @@ -896,6 +1099,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + [[package]] name = "http" version = "0.2.11" @@ -1083,6 +1295,10 @@ dependencies = [ "uuid", ] +[[package]] +name = "ibis_workspace" +version = "0.1.0" + [[package]] name = "ident_case" version = "1.0.1" @@ -1128,12 +1344,42 @@ dependencies = [ "generic-array", ] +[[package]] +name = "interpolator" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8" + +[[package]] +name = "inventory" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0508c56cfe9bfd5dfeb0c22ab9a6abfda2f27bdca422132e494266351ed8d83c" + [[package]] name = "ipnet" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.0" @@ -1179,6 +1425,152 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "leptos" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d02b78d6e38acf8199426058a0d8c4030835d84a4ee16147df25be7fed707e0" +dependencies = [ + "cfg-if", + "leptos_config", + "leptos_dom", + "leptos_macro", + "leptos_reactive", + "leptos_server", + "server_fn", + "tracing", + "typed-builder", + "typed-builder-macro", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos_config" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afcaa5db5b22b794b624e14ffe2aefae215b2d21c60a230ae2d06fe21ae5da64" +dependencies = [ + "config", + "regex", + "serde", + "thiserror", + "typed-builder", +] + +[[package]] +name = "leptos_dom" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af459b63567e8e9c921ecbe7863732dc8dcb7874eaad6826b7d3778a53ec0ea6" +dependencies = [ + "async-recursion", + "cfg-if", + "drain_filter_polyfill", + "futures", + "getrandom", + "html-escape", + "indexmap 2.1.0", + "itertools 0.10.5", + "js-sys", + "leptos_reactive", + "once_cell", + "pad-adapter", + "paste", + "rustc-hash", + "serde", + "serde_json", + "server_fn", + "smallvec", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "leptos_hot_reload" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea60376eb80a24b3ab082612d62211e3ea0fc4dee132f7ff34d5fa5a5108cd2" +dependencies = [ + "anyhow", + "camino", + "indexmap 2.1.0", + "parking_lot", + "proc-macro2", + "quote", + "rstml", + "serde", + "syn 2.0.39", + "walkdir", +] + +[[package]] +name = "leptos_macro" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e96f4c450f4b5e2ccb135c2b1328890f911ca4ee89da9ed6d582df929e6cb5" +dependencies = [ + "attribute-derive", + "cfg-if", + "convert_case", + "html-escape", + "itertools 0.11.0", + "leptos_hot_reload", + "prettyplease", + "proc-macro-error", + "proc-macro2", + "quote", + "rstml", + "server_fn_macro", + "syn 2.0.39", + "tracing", + "uuid", +] + +[[package]] +name = "leptos_reactive" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22207568e096ac153ba8da68635e3136c1ec614ea9012736fa861c05bfb2eeff" +dependencies = [ + "base64 0.21.5", + "cfg-if", + "futures", + "indexmap 2.1.0", + "js-sys", + "paste", + "pin-project", + "rustc-hash", + "self_cell", + "serde", + "serde-wasm-bindgen", + "serde_json", + "slotmap", + "thiserror", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "leptos_server" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "272d018a5adf33d10ee57e6f0f83dccc305c68613cd207e8a653aeebd4cd5b4f" +dependencies = [ + "inventory", + "lazy_static", + "leptos_macro", + "leptos_reactive", + "serde", + "server_fn", + "thiserror", + "tracing", +] + [[package]] name = "libc" version = "0.2.150" @@ -1216,6 +1608,29 @@ dependencies = [ "libc", ] +[[package]] +name = "manyhow" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b76546495d933baa165075b95c0a15e8f7ef75e53f56b19b7144d80fd52bd" +dependencies = [ + "manyhow-macros", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "manyhow-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba072c0eadade3160232e70893311f1f8903974488096e2eb8e48caba2f0cf1" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + [[package]] name = "matchit" version = "0.7.3" @@ -1244,7 +1659,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada" dependencies = [ "serde", - "toml", + "toml 0.7.8", ] [[package]] @@ -1274,6 +1689,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1336,6 +1757,16 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1451,6 +1882,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "pad-adapter" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d80efc4b6721e8be2a10a5df21a30fa0b470f1539e53d8b4e6e75faf938b63" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1474,6 +1911,18 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pem" version = "3.0.3" @@ -1556,7 +2005,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ "diff", - "yansi", + "yansi 0.5.1", +] + +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.39", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-utils" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f59e109e2f795a5070e69578c4dc101068139f74616778025ae1011d4cd41a8" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", ] [[package]] @@ -1568,6 +2061,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", + "version_check", + "yansi 1.0.0-rc.1", +] + [[package]] name = "pulldown-cmark" version = "0.9.3" @@ -1604,6 +2110,29 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "quote-use" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7b5abe3fe82fdeeb93f44d66a7b444dedf2e4827defb0a8e69c437b2de2ef94" +dependencies = [ + "quote", + "quote-use-macros", + "syn 2.0.39", +] + +[[package]] +name = "quote-use-macros" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ea44c7e20f16017a76a245bb42188517e13d16dcb1aa18044bc406cdc3f4af" +dependencies = [ + "derive-where", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "rand" version = "0.8.5" @@ -1751,12 +2280,32 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rstml" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe542870b8f59dd45ad11d382e5339c9a1047cde059be136a7016095bbdefa77" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.39", + "syn_derive", + "thiserror", +] + [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1838,6 +2387,12 @@ dependencies = [ "libc", ] +[[package]] +name = "self_cell" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba" + [[package]] name = "semver" version = "1.0.20" @@ -1856,6 +2411,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_derive" version = "1.0.193" @@ -1889,6 +2455,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_qs" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + [[package]] name = "serde_spanned" version = "0.6.4" @@ -1910,6 +2487,55 @@ dependencies = [ "serde", ] +[[package]] +name = "server_fn" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfed18dfcc8d9004579c40482c3419c07f60ffb9c5b250542edca99f508b0ce9" +dependencies = [ + "ciborium", + "const_format", + "gloo-net", + "js-sys", + "lazy_static", + "once_cell", + "proc-macro2", + "quote", + "reqwest", + "serde", + "serde_json", + "serde_qs", + "server_fn_macro_default", + "syn 2.0.39", + "thiserror", + "xxhash-rust", +] + +[[package]] +name = "server_fn_macro" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b70ae8e22546ba85500391b36c08e3fba64871be8a26557a3663a8e08acb56f" +dependencies = [ + "const_format", + "proc-macro-error", + "proc-macro2", + "quote", + "serde", + "syn 2.0.39", + "xxhash-rust", +] + +[[package]] +name = "server_fn_macro_default" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7256ba61dfadb220598db418376e7bc2a34b96df36c4dc48f24ffe161810fc0b" +dependencies = [ + "server_fn_macro", + "syn 2.0.39", +] + [[package]] name = "sha1" version = "0.10.6" @@ -1977,6 +2603,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "serde", + "version_check", +] + [[package]] name = "smallvec" version = "1.11.2" @@ -2043,6 +2679,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "sync_wrapper" version = "0.1.2" @@ -2216,6 +2864,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.7.8" @@ -2322,6 +2979,26 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typed-builder" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47c0496149861b7c95198088cbf36645016b1a0734cf350c50e2a38e070f38a" +dependencies = [ + "typed-builder-macro", +] + +[[package]] +name = "typed-builder-macro" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982ee4197351b5c9782847ef5ec1fdcaf50503fb19d68f9771adae314e72b492" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "typenum" version = "1.17.0" @@ -2358,6 +3035,18 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "untrusted" version = "0.9.0" @@ -2376,6 +3065,12 @@ dependencies = [ "serde", ] +[[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + [[package]] name = "uuid" version = "1.6.1" @@ -2637,12 +3332,24 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "xxhash-rust" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53be06678ed9e83edb1745eb72efc0bbcd7b5c3c35711a860906aed827a13d61" + [[package]] name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "yansi" +version = "1.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1367295b8f788d371ce2dbc842c7b709c73ee1364d30351dd300ec2203b12377" + [[package]] name = "zeroize" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 382f256..964a3bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,35 +1,10 @@ [package] -name = "ibis" +name = "ibis_workspace" version = "0.1.0" edition = "2021" -[dependencies] -activitypub_federation = { version = "0.5.0-beta.6", features = ["axum", "diesel"], default-features = false } -anyhow = "1.0.75" -async-trait = "0.1.74" -axum = "0.6.20" -axum-macros = "0.3.8" -bcrypt = "0.15.0" -chrono = { version = "0.4.31", features = ["serde"] } -diesel = {version = "2.1.4", features = ["postgres", "chrono", "uuid"] } -diesel-derive-newtype = "2.1.0" -diesel_migrations = "2.1.0" -diffy = "0.3.0" -enum_delegate = "0.2.0" -env_logger = { version = "0.10.1", default-features = false } -futures = "0.3.29" -hex = "0.4.3" -jsonwebtoken = "9.2.0" -rand = "0.8.5" -serde = "1.0.192" -serde_json = "1.0.108" -sha2 = "0.10.8" -tokio = { version = "1.34.0", features = ["full"] } -tracing = "0.1.40" -url = "2.4.1" -uuid = { version = "1.6.1", features = ["serde"] } - -[dev-dependencies] -once_cell = "1.18.0" -pretty_assertions = "1.4.0" -reqwest = "0.11.22" +[workspace] +members = [ + "frontend", + "backend", +] diff --git a/backend/Cargo.toml b/backend/Cargo.toml new file mode 100644 index 0000000..382f256 --- /dev/null +++ b/backend/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "ibis" +version = "0.1.0" +edition = "2021" + +[dependencies] +activitypub_federation = { version = "0.5.0-beta.6", features = ["axum", "diesel"], default-features = false } +anyhow = "1.0.75" +async-trait = "0.1.74" +axum = "0.6.20" +axum-macros = "0.3.8" +bcrypt = "0.15.0" +chrono = { version = "0.4.31", features = ["serde"] } +diesel = {version = "2.1.4", features = ["postgres", "chrono", "uuid"] } +diesel-derive-newtype = "2.1.0" +diesel_migrations = "2.1.0" +diffy = "0.3.0" +enum_delegate = "0.2.0" +env_logger = { version = "0.10.1", default-features = false } +futures = "0.3.29" +hex = "0.4.3" +jsonwebtoken = "9.2.0" +rand = "0.8.5" +serde = "1.0.192" +serde_json = "1.0.108" +sha2 = "0.10.8" +tokio = { version = "1.34.0", features = ["full"] } +tracing = "0.1.40" +url = "2.4.1" +uuid = { version = "1.6.1", features = ["serde"] } + +[dev-dependencies] +once_cell = "1.18.0" +pretty_assertions = "1.4.0" +reqwest = "0.11.22" diff --git a/migrations/00000000000000_diesel_initial_setup/down.sql b/backend/migrations/00000000000000_diesel_initial_setup/down.sql similarity index 100% rename from migrations/00000000000000_diesel_initial_setup/down.sql rename to backend/migrations/00000000000000_diesel_initial_setup/down.sql diff --git a/migrations/00000000000000_diesel_initial_setup/up.sql b/backend/migrations/00000000000000_diesel_initial_setup/up.sql similarity index 100% rename from migrations/00000000000000_diesel_initial_setup/up.sql rename to backend/migrations/00000000000000_diesel_initial_setup/up.sql diff --git a/migrations/2023-11-28-150402_ibis_setup/down.sql b/backend/migrations/2023-11-28-150402_ibis_setup/down.sql similarity index 100% rename from migrations/2023-11-28-150402_ibis_setup/down.sql rename to backend/migrations/2023-11-28-150402_ibis_setup/down.sql diff --git a/migrations/2023-11-28-150402_ibis_setup/up.sql b/backend/migrations/2023-11-28-150402_ibis_setup/up.sql similarity index 100% rename from migrations/2023-11-28-150402_ibis_setup/up.sql rename to backend/migrations/2023-11-28-150402_ibis_setup/up.sql diff --git a/src/api/article.rs b/backend/src/api/article.rs similarity index 100% rename from src/api/article.rs rename to backend/src/api/article.rs diff --git a/src/api/instance.rs b/backend/src/api/instance.rs similarity index 100% rename from src/api/instance.rs rename to backend/src/api/instance.rs diff --git a/src/api/mod.rs b/backend/src/api/mod.rs similarity index 100% rename from src/api/mod.rs rename to backend/src/api/mod.rs diff --git a/src/api/user.rs b/backend/src/api/user.rs similarity index 100% rename from src/api/user.rs rename to backend/src/api/user.rs diff --git a/src/database/article.rs b/backend/src/database/article.rs similarity index 100% rename from src/database/article.rs rename to backend/src/database/article.rs diff --git a/src/database/conflict.rs b/backend/src/database/conflict.rs similarity index 100% rename from src/database/conflict.rs rename to backend/src/database/conflict.rs diff --git a/src/database/edit.rs b/backend/src/database/edit.rs similarity index 100% rename from src/database/edit.rs rename to backend/src/database/edit.rs diff --git a/src/database/instance.rs b/backend/src/database/instance.rs similarity index 100% rename from src/database/instance.rs rename to backend/src/database/instance.rs diff --git a/src/database/mod.rs b/backend/src/database/mod.rs similarity index 100% rename from src/database/mod.rs rename to backend/src/database/mod.rs diff --git a/src/database/schema.rs b/backend/src/database/schema.rs similarity index 100% rename from src/database/schema.rs rename to backend/src/database/schema.rs diff --git a/src/database/user.rs b/backend/src/database/user.rs similarity index 100% rename from src/database/user.rs rename to backend/src/database/user.rs diff --git a/src/database/version.rs b/backend/src/database/version.rs similarity index 100% rename from src/database/version.rs rename to backend/src/database/version.rs diff --git a/src/error.rs b/backend/src/error.rs similarity index 100% rename from src/error.rs rename to backend/src/error.rs diff --git a/src/federation/activities/accept.rs b/backend/src/federation/activities/accept.rs similarity index 100% rename from src/federation/activities/accept.rs rename to backend/src/federation/activities/accept.rs diff --git a/src/federation/activities/create_article.rs b/backend/src/federation/activities/create_article.rs similarity index 100% rename from src/federation/activities/create_article.rs rename to backend/src/federation/activities/create_article.rs diff --git a/src/federation/activities/follow.rs b/backend/src/federation/activities/follow.rs similarity index 100% rename from src/federation/activities/follow.rs rename to backend/src/federation/activities/follow.rs diff --git a/src/federation/activities/mod.rs b/backend/src/federation/activities/mod.rs similarity index 100% rename from src/federation/activities/mod.rs rename to backend/src/federation/activities/mod.rs diff --git a/src/federation/activities/reject.rs b/backend/src/federation/activities/reject.rs similarity index 100% rename from src/federation/activities/reject.rs rename to backend/src/federation/activities/reject.rs diff --git a/src/federation/activities/update_local_article.rs b/backend/src/federation/activities/update_local_article.rs similarity index 100% rename from src/federation/activities/update_local_article.rs rename to backend/src/federation/activities/update_local_article.rs diff --git a/src/federation/activities/update_remote_article.rs b/backend/src/federation/activities/update_remote_article.rs similarity index 100% rename from src/federation/activities/update_remote_article.rs rename to backend/src/federation/activities/update_remote_article.rs diff --git a/src/federation/mod.rs b/backend/src/federation/mod.rs similarity index 100% rename from src/federation/mod.rs rename to backend/src/federation/mod.rs diff --git a/src/federation/objects/article.rs b/backend/src/federation/objects/article.rs similarity index 100% rename from src/federation/objects/article.rs rename to backend/src/federation/objects/article.rs diff --git a/src/federation/objects/articles_collection.rs b/backend/src/federation/objects/articles_collection.rs similarity index 100% rename from src/federation/objects/articles_collection.rs rename to backend/src/federation/objects/articles_collection.rs diff --git a/src/federation/objects/edit.rs b/backend/src/federation/objects/edit.rs similarity index 100% rename from src/federation/objects/edit.rs rename to backend/src/federation/objects/edit.rs diff --git a/src/federation/objects/edits_collection.rs b/backend/src/federation/objects/edits_collection.rs similarity index 100% rename from src/federation/objects/edits_collection.rs rename to backend/src/federation/objects/edits_collection.rs diff --git a/src/federation/objects/instance.rs b/backend/src/federation/objects/instance.rs similarity index 100% rename from src/federation/objects/instance.rs rename to backend/src/federation/objects/instance.rs diff --git a/src/federation/objects/mod.rs b/backend/src/federation/objects/mod.rs similarity index 100% rename from src/federation/objects/mod.rs rename to backend/src/federation/objects/mod.rs diff --git a/src/federation/objects/user.rs b/backend/src/federation/objects/user.rs similarity index 100% rename from src/federation/objects/user.rs rename to backend/src/federation/objects/user.rs diff --git a/src/federation/routes.rs b/backend/src/federation/routes.rs similarity index 100% rename from src/federation/routes.rs rename to backend/src/federation/routes.rs diff --git a/src/lib.rs b/backend/src/lib.rs similarity index 96% rename from src/lib.rs rename to backend/src/lib.rs index ecf2299..fe255da 100644 --- a/src/lib.rs +++ b/backend/src/lib.rs @@ -70,9 +70,7 @@ pub async fn start(hostname: &str, database_url: &str) -> MyResult<()> { .to_socket_addrs()? .next() .expect("Failed to lookup domain name"); - let server = Server::bind(&addr).serve(app.into_make_service()); - - tokio::spawn(server); + Server::bind(&addr).serve(app.into_make_service()).await?; Ok(()) } diff --git a/backend/src/main.rs b/backend/src/main.rs new file mode 100644 index 0000000..21c0d83 --- /dev/null +++ b/backend/src/main.rs @@ -0,0 +1,15 @@ +use ibis::error::MyResult; +use ibis::start; +use tracing::log::LevelFilter; + +#[tokio::main] +pub async fn main() -> MyResult<()> { + env_logger::builder() + .filter_level(LevelFilter::Warn) + .filter_module("activitypub_federation", LevelFilter::Info) + .filter_module("ibis", LevelFilter::Info) + .init(); + let database_url = "postgres://ibis:password@localhost:5432/ibis"; + start("localhost:8131", database_url).await?; + Ok(()) +} diff --git a/src/utils.rs b/backend/src/utils.rs similarity index 100% rename from src/utils.rs rename to backend/src/utils.rs diff --git a/tests/common.rs b/backend/tests/common.rs similarity index 100% rename from tests/common.rs rename to backend/tests/common.rs diff --git a/tests/scripts/start_dev_db.sh b/backend/tests/scripts/start_dev_db.sh similarity index 100% rename from tests/scripts/start_dev_db.sh rename to backend/tests/scripts/start_dev_db.sh diff --git a/tests/scripts/stop_dev_db.sh b/backend/tests/scripts/stop_dev_db.sh similarity index 100% rename from tests/scripts/stop_dev_db.sh rename to backend/tests/scripts/stop_dev_db.sh diff --git a/tests/test.rs b/backend/tests/test.rs similarity index 100% rename from tests/test.rs rename to backend/tests/test.rs diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml new file mode 100644 index 0000000..6744b67 --- /dev/null +++ b/frontend/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "frontend" +version = "0.1.0" +edition = "2021" + +[dependencies] +leptos = { version = "0.5.4", features = ["csr"] } +reqwest = { version = "0.11.22", features = ["json"] } +console_log = "1" +console_error_panic_hook = "0.1" +log = "0.4" +serde = { version = "1", features = ["derive"] } diff --git a/frontend/dist/frontend-0e306a0cbb659ffacc2bde4bf6be791bdf3c4fd12ec49427513525c99e29cee2c56ae2ebb40ced499f14e919ae9c9bc1.js b/frontend/dist/frontend-0e306a0cbb659ffacc2bde4bf6be791bdf3c4fd12ec49427513525c99e29cee2c56ae2ebb40ced499f14e919ae9c9bc1.js new file mode 100644 index 0000000..3d138bf --- /dev/null +++ b/frontend/dist/frontend-0e306a0cbb659ffacc2bde4bf6be791bdf3c4fd12ec49427513525c99e29cee2c56ae2ebb40ced499f14e919ae9c9bc1.js @@ -0,0 +1,763 @@ +let wasm; + +const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); + +if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; + +let cachedUint8Memory0 = null; + +function getUint8Memory0() { + if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { + cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8Memory0; +} + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); +} + +const heap = new Array(128).fill(undefined); + +heap.push(undefined, null, true, false); + +let heap_next = heap.length; + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +function getObject(idx) { return heap[idx]; } + +let WASM_VECTOR_LEN = 0; + +const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); + +const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); +} + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; +}); + +function passStringToWasm0(arg, malloc, realloc) { + + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8Memory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +function isLikeNone(x) { + return x === undefined || x === null; +} + +let cachedInt32Memory0 = null; + +function getInt32Memory0() { + if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { + cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachedInt32Memory0; +} + +function dropObject(idx) { + if (idx < 132) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +function debugString(val) { + // primitive types + const type = typeof val; + if (type == 'number' || type == 'boolean' || val == null) { + return `${val}`; + } + if (type == 'string') { + return `"${val}"`; + } + if (type == 'symbol') { + const description = val.description; + if (description == null) { + return 'Symbol'; + } else { + return `Symbol(${description})`; + } + } + if (type == 'function') { + const name = val.name; + if (typeof name == 'string' && name.length > 0) { + return `Function(${name})`; + } else { + return 'Function'; + } + } + // objects + if (Array.isArray(val)) { + const length = val.length; + let debug = '['; + if (length > 0) { + debug += debugString(val[0]); + } + for(let i = 1; i < length; i++) { + debug += ', ' + debugString(val[i]); + } + debug += ']'; + return debug; + } + // Test for built-in + const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); + let className; + if (builtInMatches.length > 1) { + className = builtInMatches[1]; + } else { + // Failed to match the standard '[object ClassName]' + return toString.call(val); + } + if (className == 'Object') { + // we're a user defined class or Object + // JSON.stringify avoids problems with cycles, and is generally much + // easier than looping through ownProperties of `val`. + try { + return 'Object(' + JSON.stringify(val) + ')'; + } catch (_) { + return 'Object'; + } + } + // errors + if (val instanceof Error) { + return `${val.name}: ${val.message}\n${val.stack}`; + } + // TODO we could test for more things here, like `Set`s and `Map`s. + return className; +} + +function makeMutClosure(arg0, arg1, dtor, f) { + const state = { a: arg0, b: arg1, cnt: 1, dtor }; + const real = (...args) => { + // First up with a closure we increment the internal reference + // count. This ensures that the Rust closure environment won't + // be deallocated while we're invoking it. + state.cnt++; + const a = state.a; + state.a = 0; + try { + return f(a, state.b, ...args); + } finally { + if (--state.cnt === 0) { + wasm.__wbindgen_export_2.get(state.dtor)(a, state.b); + + } else { + state.a = a; + } + } + }; + real.original = state; + + return real; +} +function __wbg_adapter_28(arg0, arg1) { + wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h317d618a1c63285e(arg0, arg1); +} + +function __wbg_adapter_31(arg0, arg1, arg2) { + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5924f6ec2668bdab(arg0, arg1, addHeapObject(arg2)); +} + +function __wbg_adapter_34(arg0, arg1, arg2) { + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hecf0bddf191eb724(arg0, arg1, addHeapObject(arg2)); +} + +function getCachedStringFromWasm0(ptr, len) { + if (ptr === 0) { + return getObject(len); + } else { + return getStringFromWasm0(ptr, len); + } +} + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_exn_store(addHeapObject(e)); + } +} + +async function __wbg_load(module, imports) { + if (typeof Response === 'function' && module instanceof Response) { + if (typeof WebAssembly.instantiateStreaming === 'function') { + try { + return await WebAssembly.instantiateStreaming(module, imports); + + } catch (e) { + if (module.headers.get('Content-Type') != 'application/wasm') { + console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); + + } else { + throw e; + } + } + } + + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); + + } else { + const instance = await WebAssembly.instantiate(module, imports); + + if (instance instanceof WebAssembly.Instance) { + return { instance, module }; + + } else { + return instance; + } + } +} + +function __wbg_get_imports() { + const imports = {}; + imports.wbg = {}; + imports.wbg.__wbindgen_string_new = function(arg0, arg1) { + const ret = getStringFromWasm0(arg0, arg1); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_object_clone_ref = function(arg0) { + const ret = getObject(arg0); + return addHeapObject(ret); + }; + imports.wbg.__wbg_fetch_b5d6bebed1e6c2d2 = function(arg0) { + const ret = fetch(getObject(arg0)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_error_f851667af71bcfc6 = function(arg0, arg1) { + var v0 = getCachedStringFromWasm0(arg0, arg1); + if (arg0 !== 0) { wasm.__wbindgen_free(arg0, arg1, 1); } + console.error(v0); +}; +imports.wbg.__wbg_new_abda76e883ba8a5f = function() { + const ret = new Error(); + return addHeapObject(ret); +}; +imports.wbg.__wbg_stack_658279fe44541cf6 = function(arg0, arg1) { + const ret = getObject(arg1).stack; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; +}; +imports.wbg.__wbindgen_is_undefined = function(arg0) { + const ret = getObject(arg0) === undefined; + return ret; +}; +imports.wbg.__wbindgen_is_null = function(arg0) { + const ret = getObject(arg0) === null; + return ret; +}; +imports.wbg.__wbindgen_is_falsy = function(arg0) { + const ret = !getObject(arg0); + return ret; +}; +imports.wbg.__wbindgen_string_get = function(arg0, arg1) { + const obj = getObject(arg1); + const ret = typeof(obj) === 'string' ? obj : undefined; + var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; +}; +imports.wbg.__wbindgen_cb_drop = function(arg0) { + const obj = takeObject(arg0).original; + if (obj.cnt-- == 1) { + obj.a = 0; + return true; + } + const ret = false; + return ret; +}; +imports.wbg.__wbg_instanceof_Window_cde2416cf5126a72 = function(arg0) { + let result; + try { + result = getObject(arg0) instanceof Window; + } catch (_) { + result = false; + } + const ret = result; + return ret; +}; +imports.wbg.__wbg_document_183cf1eecfdbffee = function(arg0) { + const ret = getObject(arg0).document; + return isLikeNone(ret) ? 0 : addHeapObject(ret); +}; +imports.wbg.__wbg_body_11da0c1aa9610cb3 = function(arg0) { + const ret = getObject(arg0).body; + return isLikeNone(ret) ? 0 : addHeapObject(ret); +}; +imports.wbg.__wbg_createComment_3b18d83b12cfbf48 = function(arg0, arg1, arg2) { + var v0 = getCachedStringFromWasm0(arg1, arg2); + const ret = getObject(arg0).createComment(v0); + return addHeapObject(ret); +}; +imports.wbg.__wbg_createDocumentFragment_acf4f9887c44b09f = function(arg0) { + const ret = getObject(arg0).createDocumentFragment(); + return addHeapObject(ret); +}; +imports.wbg.__wbg_createElement_9ce3fdea8322ff34 = function() { return handleError(function (arg0, arg1, arg2) { + var v0 = getCachedStringFromWasm0(arg1, arg2); + const ret = getObject(arg0).createElement(v0); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_createTextNode_01a7250c5ca46b04 = function(arg0, arg1, arg2) { + var v0 = getCachedStringFromWasm0(arg1, arg2); + const ret = getObject(arg0).createTextNode(v0); + return addHeapObject(ret); +}; +imports.wbg.__wbg_namespaceURI_2dd94d0147ffddf2 = function(arg0, arg1) { + const ret = getObject(arg1).namespaceURI; + var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; +}; +imports.wbg.__wbg_setinnerHTML_b88bf159b62c2334 = function(arg0, arg1, arg2) { + var v0 = getCachedStringFromWasm0(arg1, arg2); + getObject(arg0).innerHTML = v0; +}; +imports.wbg.__wbg_outerHTML_72dcf3aa34725f10 = function(arg0, arg1) { + const ret = getObject(arg1).outerHTML; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; +}; +imports.wbg.__wbg_removeAttribute_dbd76981f9bb9f59 = function() { return handleError(function (arg0, arg1, arg2) { + var v0 = getCachedStringFromWasm0(arg1, arg2); + getObject(arg0).removeAttribute(v0); +}, arguments) }; +imports.wbg.__wbg_setAttribute_aebcae2169f2f869 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + var v0 = getCachedStringFromWasm0(arg1, arg2); + var v1 = getCachedStringFromWasm0(arg3, arg4); + getObject(arg0).setAttribute(v0, v1); +}, arguments) }; +imports.wbg.__wbg_before_cf3a1481df28e2d5 = function() { return handleError(function (arg0, arg1) { + getObject(arg0).before(getObject(arg1)); +}, arguments) }; +imports.wbg.__wbg_remove_e8b7a30da3792f66 = function(arg0) { + getObject(arg0).remove(); +}; +imports.wbg.__wbg_append_a7f308e9b0724ea2 = function() { return handleError(function (arg0, arg1, arg2) { + getObject(arg0).append(getObject(arg1), getObject(arg2)); +}, arguments) }; +imports.wbg.__wbg_value_5e860795f53217cd = function(arg0, arg1) { + const ret = getObject(arg1).value; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; +}; +imports.wbg.__wbg_parentNode_e1c214fc3f362af0 = function(arg0) { + const ret = getObject(arg0).parentNode; + return isLikeNone(ret) ? 0 : addHeapObject(ret); +}; +imports.wbg.__wbg_childNodes_e62200b977bdb1a0 = function(arg0) { + const ret = getObject(arg0).childNodes; + return addHeapObject(ret); +}; +imports.wbg.__wbg_previousSibling_de863aa81066e2fe = function(arg0) { + const ret = getObject(arg0).previousSibling; + return isLikeNone(ret) ? 0 : addHeapObject(ret); +}; +imports.wbg.__wbg_nextSibling_d029031876ed1b1b = function(arg0) { + const ret = getObject(arg0).nextSibling; + return isLikeNone(ret) ? 0 : addHeapObject(ret); +}; +imports.wbg.__wbg_textContent_d69d000f6081b514 = function(arg0, arg1) { + const ret = getObject(arg1).textContent; + var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; +}; +imports.wbg.__wbg_settextContent_57c7c19d2b0e7614 = function(arg0, arg1, arg2) { + var v0 = getCachedStringFromWasm0(arg1, arg2); + getObject(arg0).textContent = v0; +}; +imports.wbg.__wbg_appendChild_2e6a6c9d1f0d443d = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg0).appendChild(getObject(arg1)); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_cloneNode_df9cbf9711e3707d = function() { return handleError(function (arg0) { + const ret = getObject(arg0).cloneNode(); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_newwithstrandinit_29038da14d09e330 = function() { return handleError(function (arg0, arg1, arg2) { + var v0 = getCachedStringFromWasm0(arg0, arg1); + const ret = new Request(v0, getObject(arg2)); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_signal_1ed842bebd6ae322 = function(arg0) { + const ret = getObject(arg0).signal; + return addHeapObject(ret); +}; +imports.wbg.__wbg_new_e4960143e41697a4 = function() { return handleError(function () { + const ret = new AbortController(); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_abort_8355f201f30300bb = function(arg0) { + getObject(arg0).abort(); +}; +imports.wbg.__wbg_setdata_21158d298225cbec = function(arg0, arg1, arg2) { + var v0 = getCachedStringFromWasm0(arg1, arg2); + getObject(arg0).data = v0; +}; +imports.wbg.__wbg_addEventListener_0f2891b0794e07fa = function() { return handleError(function (arg0, arg1, arg2, arg3) { + var v0 = getCachedStringFromWasm0(arg1, arg2); + getObject(arg0).addEventListener(v0, getObject(arg3)); +}, arguments) }; +imports.wbg.__wbg_addEventListener_51709b9747ad8980 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + var v0 = getCachedStringFromWasm0(arg1, arg2); + getObject(arg0).addEventListener(v0, getObject(arg3), getObject(arg4)); +}, arguments) }; +imports.wbg.__wbg_length_eae3bc233f10d60d = function(arg0) { + const ret = getObject(arg0).length; + return ret; +}; +imports.wbg.__wbg_instanceof_Response_944e2745b5db71f5 = function(arg0) { + let result; + try { + result = getObject(arg0) instanceof Response; + } catch (_) { + result = false; + } + const ret = result; + return ret; +}; +imports.wbg.__wbg_url_1f609e63ff1a7983 = function(arg0, arg1) { + const ret = getObject(arg1).url; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; +}; +imports.wbg.__wbg_status_7841bb47be2a8f16 = function(arg0) { + const ret = getObject(arg0).status; + return ret; +}; +imports.wbg.__wbg_headers_ea7ef583d1564b08 = function(arg0) { + const ret = getObject(arg0).headers; + return addHeapObject(ret); +}; +imports.wbg.__wbg_arrayBuffer_e32d72b052ba31d7 = function() { return handleError(function (arg0) { + const ret = getObject(arg0).arrayBuffer(); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_instanceof_ShadowRoot_f85f709c953844de = function(arg0) { + let result; + try { + result = getObject(arg0) instanceof ShadowRoot; + } catch (_) { + result = false; + } + const ret = result; + return ret; +}; +imports.wbg.__wbg_host_73c8e95bf9b31ccd = function(arg0) { + const ret = getObject(arg0).host; + return addHeapObject(ret); +}; +imports.wbg.__wbg_target_6efb4504c149139f = function(arg0) { + const ret = getObject(arg0).target; + return isLikeNone(ret) ? 0 : addHeapObject(ret); +}; +imports.wbg.__wbg_cancelBubble_ee3f70328e901584 = function(arg0) { + const ret = getObject(arg0).cancelBubble; + return ret; +}; +imports.wbg.__wbg_composedPath_ee37eece046b69a2 = function(arg0) { + const ret = getObject(arg0).composedPath(); + return addHeapObject(ret); +}; +imports.wbg.__wbg_new_19676474aa414d62 = function() { return handleError(function () { + const ret = new Headers(); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_append_feec4143bbf21904 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + var v0 = getCachedStringFromWasm0(arg1, arg2); + var v1 = getCachedStringFromWasm0(arg3, arg4); + getObject(arg0).append(v0, v1); +}, arguments) }; +imports.wbg.__wbg_fetch_701fcd2bde06379a = function(arg0, arg1) { + const ret = getObject(arg0).fetch(getObject(arg1)); + return addHeapObject(ret); +}; +imports.wbg.__wbg_debug_2ef5d777cf4811fa = function(arg0) { + console.debug(getObject(arg0)); +}; +imports.wbg.__wbg_error_f0a6627f4b23c19d = function(arg0) { + console.error(getObject(arg0)); +}; +imports.wbg.__wbg_info_3ca7870690403fee = function(arg0) { + console.info(getObject(arg0)); +}; +imports.wbg.__wbg_log_7811587c4c6d2844 = function(arg0) { + console.log(getObject(arg0)); +}; +imports.wbg.__wbg_warn_4affe1093892a4ef = function(arg0) { + console.warn(getObject(arg0)); +}; +imports.wbg.__wbindgen_is_function = function(arg0) { + const ret = typeof(getObject(arg0)) === 'function'; + return ret; +}; +imports.wbg.__wbg_queueMicrotask_e5949c35d772a669 = function(arg0) { + queueMicrotask(getObject(arg0)); +}; +imports.wbg.__wbg_queueMicrotask_2be8b97a81fe4d00 = function(arg0) { + const ret = getObject(arg0).queueMicrotask; + return addHeapObject(ret); +}; +imports.wbg.__wbg_get_4a9aa5157afeb382 = function(arg0, arg1) { + const ret = getObject(arg0)[arg1 >>> 0]; + return addHeapObject(ret); +}; +imports.wbg.__wbg_newnoargs_ccdcae30fd002262 = function(arg0, arg1) { + var v0 = getCachedStringFromWasm0(arg0, arg1); + const ret = new Function(v0); + return addHeapObject(ret); +}; +imports.wbg.__wbg_call_669127b9d730c650 = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg0).call(getObject(arg1)); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_call_53fc3abd42e24ec8 = function() { return handleError(function (arg0, arg1, arg2) { + const ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_next_1989a20442400aaa = function() { return handleError(function (arg0) { + const ret = getObject(arg0).next(); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_next_15da6a3df9290720 = function(arg0) { + const ret = getObject(arg0).next; + return addHeapObject(ret); +}; +imports.wbg.__wbg_done_bc26bf4ada718266 = function(arg0) { + const ret = getObject(arg0).done; + return ret; +}; +imports.wbg.__wbg_value_0570714ff7d75f35 = function(arg0) { + const ret = getObject(arg0).value; + return addHeapObject(ret); +}; +imports.wbg.__wbg_is_c74aa9bb973d6109 = function(arg0, arg1) { + const ret = Object.is(getObject(arg0), getObject(arg1)); + return ret; +}; +imports.wbg.__wbg_new_c728d68b8b34487e = function() { + const ret = new Object(); + return addHeapObject(ret); +}; +imports.wbg.__wbg_iterator_7ee1a391d310f8e4 = function() { + const ret = Symbol.iterator; + return addHeapObject(ret); +}; +imports.wbg.__wbg_resolve_a3252b2860f0a09e = function(arg0) { + const ret = Promise.resolve(getObject(arg0)); + return addHeapObject(ret); +}; +imports.wbg.__wbg_then_89e1c559530b85cf = function(arg0, arg1) { + const ret = getObject(arg0).then(getObject(arg1)); + return addHeapObject(ret); +}; +imports.wbg.__wbg_then_1bbc9edafd859b06 = function(arg0, arg1, arg2) { + const ret = getObject(arg0).then(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); +}; +imports.wbg.__wbg_globalThis_17eff828815f7d84 = function() { return handleError(function () { + const ret = globalThis.globalThis; + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_self_3fad056edded10bd = function() { return handleError(function () { + const ret = self.self; + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_window_a4f46c98a61d4089 = function() { return handleError(function () { + const ret = window.window; + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_global_46f939f6541643c5 = function() { return handleError(function () { + const ret = global.global; + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_new_d8a000788389a31e = function(arg0) { + const ret = new Uint8Array(getObject(arg0)); + return addHeapObject(ret); +}; +imports.wbg.__wbg_newwithbyteoffsetandlength_2dc04d99088b15e3 = function(arg0, arg1, arg2) { + const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); + return addHeapObject(ret); +}; +imports.wbg.__wbg_length_a5587d6cd79ab197 = function(arg0) { + const ret = getObject(arg0).length; + return ret; +}; +imports.wbg.__wbg_set_dcfd613a3420f908 = function(arg0, arg1, arg2) { + getObject(arg0).set(getObject(arg1), arg2 >>> 0); +}; +imports.wbg.__wbindgen_is_object = function(arg0) { + const val = getObject(arg0); + const ret = typeof(val) === 'object' && val !== null; + return ret; +}; +imports.wbg.__wbg_buffer_344d9b41efe96da7 = function(arg0) { + const ret = getObject(arg0).buffer; + return addHeapObject(ret); +}; +imports.wbg.__wbg_stringify_4039297315a25b00 = function() { return handleError(function (arg0) { + const ret = JSON.stringify(getObject(arg0)); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_get_2aff440840bb6202 = function() { return handleError(function (arg0, arg1) { + const ret = Reflect.get(getObject(arg0), getObject(arg1)); + return addHeapObject(ret); +}, arguments) }; +imports.wbg.__wbg_has_cdf8b85f6e903c80 = function() { return handleError(function (arg0, arg1) { + const ret = Reflect.has(getObject(arg0), getObject(arg1)); + return ret; +}, arguments) }; +imports.wbg.__wbg_set_40f7786a25a9cc7e = function() { return handleError(function (arg0, arg1, arg2) { + const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2)); + return ret; +}, arguments) }; +imports.wbg.__wbindgen_debug_string = function(arg0, arg1) { + const ret = debugString(getObject(arg1)); + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; +}; +imports.wbg.__wbindgen_object_drop_ref = function(arg0) { + takeObject(arg0); +}; +imports.wbg.__wbindgen_throw = function(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); +}; +imports.wbg.__wbindgen_memory = function() { + const ret = wasm.memory; + return addHeapObject(ret); +}; +imports.wbg.__wbindgen_closure_wrapper4878 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 530, __wbg_adapter_28); + return addHeapObject(ret); +}; +imports.wbg.__wbindgen_closure_wrapper4880 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 528, __wbg_adapter_31); + return addHeapObject(ret); +}; +imports.wbg.__wbindgen_closure_wrapper10314 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 634, __wbg_adapter_34); + return addHeapObject(ret); +}; + +return imports; +} + +function __wbg_init_memory(imports, maybe_memory) { + +} + +function __wbg_finalize_init(instance, module) { + wasm = instance.exports; + __wbg_init.__wbindgen_wasm_module = module; + cachedInt32Memory0 = null; + cachedUint8Memory0 = null; + + wasm.__wbindgen_start(); + return wasm; +} + +function initSync(module) { + if (wasm !== undefined) return wasm; + + const imports = __wbg_get_imports(); + + __wbg_init_memory(imports); + + if (!(module instanceof WebAssembly.Module)) { + module = new WebAssembly.Module(module); + } + + const instance = new WebAssembly.Instance(module, imports); + + return __wbg_finalize_init(instance, module); +} + +async function __wbg_init(input) { + if (wasm !== undefined) return wasm; + + if (typeof input === 'undefined') { + input = new URL('frontend-0e306a0cbb659ffacc2bde4bf6be791bdf3c4fd12ec49427513525c99e29cee2c56ae2ebb40ced499f14e919ae9c9bc1_bg.wasm', import.meta.url); + } + const imports = __wbg_get_imports(); + + if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { + input = fetch(input); + } + + __wbg_init_memory(imports); + + const { instance, module } = await __wbg_load(await input, imports); + + return __wbg_finalize_init(instance, module); +} + +export { initSync } +export default __wbg_init; diff --git a/frontend/dist/frontend-0e306a0cbb659ffacc2bde4bf6be791bdf3c4fd12ec49427513525c99e29cee2c56ae2ebb40ced499f14e919ae9c9bc1_bg.wasm b/frontend/dist/frontend-0e306a0cbb659ffacc2bde4bf6be791bdf3c4fd12ec49427513525c99e29cee2c56ae2ebb40ced499f14e919ae9c9bc1_bg.wasm new file mode 100644 index 0000000..7c7cdc9 Binary files /dev/null and b/frontend/dist/frontend-0e306a0cbb659ffacc2bde4bf6be791bdf3c4fd12ec49427513525c99e29cee2c56ae2ebb40ced499f14e919ae9c9bc1_bg.wasm differ diff --git a/frontend/dist/index.html b/frontend/dist/index.html new file mode 100644 index 0000000..72cc1b3 --- /dev/null +++ b/frontend/dist/index.html @@ -0,0 +1,153 @@ + + + + + + + + + \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..3134896 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,19 @@ + + + + + + + + \ No newline at end of file diff --git a/frontend/src/main.rs b/frontend/src/main.rs new file mode 100644 index 0000000..fb49130 --- /dev/null +++ b/frontend/src/main.rs @@ -0,0 +1,101 @@ +use leptos::error::Result; +use leptos::*; +use serde::{Deserialize, Serialize}; + +pub fn main() { + _ = console_log::init_with_level(log::Level::Debug); + console_error_panic_hook::set_once(); + mount_to_body(fetch_example) +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct Cat { + url: String, +} + +type CatCount = usize; + +async fn fetch_cats(count: CatCount) -> Result> { + if count > 0 { + // make the request + let res = reqwest::get(&format!( + "https://api.thecatapi.com/v1/images/search?limit={count}", + )) + .await? + .json::>() + .await? + // extract the URL field for each cat + .into_iter() + .take(count) + .map(|cat| cat.url) + .collect::>(); + Ok(res) + } else { + Ok(vec![]) + } +} + +pub fn fetch_example() -> impl IntoView { + let (cat_count, set_cat_count) = create_signal::(0); + + // we use local_resource here because + // 1) our error type isn't serializable/deserializable + // 2) we're not doing server-side rendering in this example anyway + // (during SSR, create_resource will begin loading on the server and resolve on the client) + let cats = create_local_resource(move || cat_count.get(), fetch_cats); + + let fallback = move |errors: RwSignal| { + let error_list = move || { + errors.with(|errors| { + errors + .iter() + .map(|(_, e)| view! {
  • {e.to_string()}
  • }) + .collect_view() + }) + }; + + view! { +
    +

    "Error"

    +
      {error_list}
    +
    + } + }; + + // the renderer can handle Option<_> and Result<_> states + // by displaying nothing for None if the resource is still loading + // and by using the ErrorBoundary fallback to catch Err(_) + // so we'll just use `.and_then()` to map over the happy path + let cats_view = move || { + cats.and_then(|data| { + data.iter() + .map(|s| view! {

    }) + .collect_view() + }) + }; + + view! { +
    + + "Loading (Suspense Fallback)..."
    } + }> + +
    + {cats_view} +
    +
    + + + } +} diff --git a/src/main.rs b/src/main.rs index 21c0d83..304dabf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,3 @@ -use ibis::error::MyResult; -use ibis::start; -use tracing::log::LevelFilter; - -#[tokio::main] -pub async fn main() -> MyResult<()> { - env_logger::builder() - .filter_level(LevelFilter::Warn) - .filter_module("activitypub_federation", LevelFilter::Info) - .filter_module("ibis", LevelFilter::Info) - .init(); - let database_url = "postgres://ibis:password@localhost:5432/ibis"; - start("localhost:8131", database_url).await?; - Ok(()) +pub async fn main() { + unimplemented!(); }