From d3ff40ef016f1dee39862580bb270e1789f4dcf2 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 13 Mar 2025 19:20:36 -0700 Subject: [PATCH] Proof of concept: move the window and app context checks into the executor --- Cargo.lock | 358 +++++++++++--------- crates/gpui/src/app.rs | 30 +- crates/gpui/src/app/async_context.rs | 164 ++++----- crates/gpui/src/app/context.rs | 14 +- crates/gpui/src/app/entity_map.rs | 33 +- crates/gpui/src/app/test_context.rs | 55 ++- crates/gpui/src/executor.rs | 126 +++---- crates/gpui/src/gpui.rs | 32 +- crates/gpui/src/platform.rs | 107 +++++- crates/gpui/src/platform/mac/dispatcher.rs | 17 +- crates/gpui/src/platform/test/dispatcher.rs | 47 ++- 11 files changed, 508 insertions(+), 475 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1f7ec5ced2..f3fe34d840 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -257,9 +257,9 @@ checksum = "34cd60c5e3152cef0a592f1b296f1cc93715d89d2551d85315828c3a09575ff4" [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "approx" @@ -643,7 +643,7 @@ dependencies = [ "smol", "terminal_view", "text", - "toml 0.8.20", + "toml 0.8.19", "ui", "util", "workspace", @@ -745,9 +745,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.20" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310c9bcae737a48ef5cdee3174184e6d548b292739ede61a1f955ef76a738861" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" dependencies = [ "deflate64", "flate2", @@ -1031,9 +1031,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.86" +version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", @@ -1199,9 +1199,9 @@ dependencies = [ [[package]] name = "aws-config" -version = "1.5.16" +version = "1.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50236e4d60fe8458de90a71c0922c761e41755adf091b1b03de1cef537179915" +checksum = "90aff65e86db5fe300752551c1b015ef72b708ac54bded8ef43d0d53cb7cb0b1" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1209,7 +1209,7 @@ dependencies = [ "aws-sdk-ssooidc", "aws-sdk-sts", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.61.1", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1272,7 +1272,7 @@ dependencies = [ "aws-sigv4", "aws-smithy-async", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -1290,15 +1290,15 @@ dependencies = [ [[package]] name = "aws-sdk-bedrockruntime" -version = "1.74.0" +version = "1.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6938541d1948a543bca23303fec4cff9c36bf0e63b8fa3ae1b337bcb9d5b81af" +checksum = "b538f72f5ab8d23de44aacd109788c37e268fe9f4d060168714a12514d73b434" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.61.1", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1314,14 +1314,14 @@ dependencies = [ [[package]] name = "aws-sdk-kinesis" -version = "1.61.0" +version = "1.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89f2163d8704e8fdcd51ec6c2e0441c418471e422ee9690451b17a1c46344e1a" +checksum = "7963cf7a0f49ba4f8351044751f4d42c003c4a5f31d9e084f0d0e68b6fb8b8cf" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1336,9 +1336,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.76.0" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e83401ad7287ad15244d557e35502c2a94105ca5b41d656c391f1a4fc04ca2" +checksum = "1c7ce6d85596c4bcb3aba8ad5bb134b08e204c8a475c9999c1af9290f80aa8ad" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1346,7 +1346,7 @@ dependencies = [ "aws-smithy-async", "aws-smithy-checksums", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1370,14 +1370,14 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.58.0" +version = "1.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ff718c9ee45cc1ebd4774a0e086bb80a6ab752b4902edf1c9f56b86ee1f770" +checksum = "e65ff295979977039a25f5a0bf067a64bc5e6aa38f3cef4037cf42516265553c" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.61.1", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1392,14 +1392,14 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.59.0" +version = "1.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5183e088715cc135d8d396fdd3bc02f018f0da4c511f53cb8d795b6a31c55809" +checksum = "91430a60f754f235688387b75ee798ef00cfd09709a582be2b7525ebb5306d4f" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.61.1", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1414,14 +1414,14 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.59.0" +version = "1.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9f944ef032717596639cea4a2118a3a457268ef51bbb5fde9637e54c465da00" +checksum = "9276e139d39fff5a0b0c984fc2d30f970f9a202da67234f948fda02e5bea1dbe" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.61.1", "aws-smithy-json", "aws-smithy-query", "aws-smithy-runtime", @@ -1443,7 +1443,7 @@ checksum = "9bfe75fad52793ce6dec0dc3d4b1f388f038b5eb866c8d4d7f3a8e21b5ea5051" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-runtime-api", "aws-smithy-types", "bytes 1.10.1", @@ -1481,7 +1481,7 @@ version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f45a1c384d7a393026bc5f5c177105aa9fa68e4749653b985707ac27d77295" dependencies = [ - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-types", "bytes 1.10.1", "crc32c", @@ -1499,9 +1499,9 @@ dependencies = [ [[package]] name = "aws-smithy-eventstream" -version = "0.60.6" +version = "0.60.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b18559a41e0c909b77625adf2b8c50de480a8041e5e4a3f5f7d177db70abc5a" +checksum = "7c45d3dddac16c5c59d553ece225a88870cf81b7b813c9cc17b78cf4685eac7a" dependencies = [ "aws-smithy-types", "bytes 1.10.1", @@ -1529,6 +1529,27 @@ dependencies = [ "tracing", ] +[[package]] +name = "aws-smithy-http" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f276f21c7921fe902826618d1423ae5bf74cf8c1b8472aee8434f3dfd31824" +dependencies = [ + "aws-smithy-eventstream", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes 1.10.1", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http-body 0.4.6", + "once_cell", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", +] + [[package]] name = "aws-smithy-json" version = "0.61.2" @@ -1555,7 +1576,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d526a12d9ed61fadefda24abe2e682892ba288c2018bcb38b1b4c111d13f6d92" dependencies = [ "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-runtime-api", "aws-smithy-types", "bytes 1.10.1", @@ -1594,9 +1615,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.13" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7b8a53819e42f10d0821f56da995e1470b199686a1809168db6ca485665f042" +checksum = "836155caafba616c0ff9b07944324785de2ab016141c3550bd1c07882f8cee8f" dependencies = [ "base64-simd", "bytes 1.10.1", @@ -1829,7 +1850,7 @@ dependencies = [ "bitflags 2.8.0", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -1852,7 +1873,7 @@ dependencies = [ "bitflags 2.8.0", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.12.1", "log", "prettyplease", "proc-macro2", @@ -1987,9 +2008,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.6.1" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "675f87afced0413c9bb02843499dbbd3882a237645883f71a2b59644a6d2f753" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec", @@ -2385,9 +2406,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.19.2" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" dependencies = [ "camino", "cargo-platform", @@ -2404,7 +2425,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fbd1fe9db3ebf71b89060adaf7b0504c2d6a425cf061313099547e382c2e472" dependencies = [ "serde", - "toml 0.8.20", + "toml 0.8.19", ] [[package]] @@ -2438,7 +2459,7 @@ dependencies = [ "serde_json", "syn 2.0.90", "tempfile", - "toml 0.8.20", + "toml 0.8.19", ] [[package]] @@ -2456,14 +2477,14 @@ dependencies = [ "serde_json", "syn 2.0.90", "tempfile", - "toml 0.8.20", + "toml 0.8.19", ] [[package]] name = "cc" -version = "1.2.12" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755717a7de9ec452bf7f3f1a3099085deabd7f2962b861dae91ecd7a365903d2" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ "jobserver", "libc", @@ -2538,9 +2559,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -2548,7 +2569,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-targets 0.52.6", ] [[package]] @@ -2608,9 +2629,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.31" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -2618,9 +2639,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.31" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -2640,9 +2661,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.28" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -2732,9 +2753,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.53" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24a03c8b52922d68a1589ad61032f2c1aa5a8158d2aa0d93c6e9534944bbad6" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ "cc", ] @@ -2912,7 +2933,7 @@ dependencies = [ "thiserror 1.0.69", "time", "tokio", - "toml 0.8.20", + "toml 0.8.19", "tower", "tower-http 0.4.4", "tracing", @@ -2973,7 +2994,7 @@ name = "collections" version = "0.1.0" dependencies = [ "indexmap", - "rustc-hash 2.1.1", + "rustc-hash 2.1.0", ] [[package]] @@ -3445,7 +3466,7 @@ dependencies = [ "hashbrown 0.14.5", "log", "regalloc2", - "rustc-hash 2.1.1", + "rustc-hash 2.1.0", "serde", "smallvec", "target-lexicon 0.13.2", @@ -3691,9 +3712,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7747ac3a66a06f4ee6718686c8ea976d2d05fb30ada93ebd76b3f9aef97257c" +checksum = "07e9666f4a9a948d4f1dff0c08a4512b0f7c86414b23960104c243c10d79f4c3" dependencies = [ "ctor-proc-macro", "dtor", @@ -3904,9 +3925,9 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.19" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case 0.4.0", "proc-macro2", @@ -4081,9 +4102,9 @@ dependencies = [ [[package]] name = "dtor" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf39a0bfd1f94d62ffdb2802a7e6244c0f34f6ebacf5d4c26547d08cd1d67a5" +checksum = "222ef136a1c687d4aa0395c175f2c4586e379924c352fd02f7870cf7de783c23" dependencies = [ "dtor-proc-macro", ] @@ -4249,14 +4270,14 @@ dependencies = [ [[package]] name = "embed-resource" -version = "3.0.2" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbc6e0d8e0c03a655b53ca813f0463d2c956bc4db8138dbc89f120b066551e3" +checksum = "4762ce03154ba57ebaeee60cc631901ceae4f18219cbb874e464347471594742" dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.8.20", + "toml 0.8.19", "vswhom", "winreg 0.52.0", ] @@ -4553,7 +4574,7 @@ dependencies = [ "semantic_version", "serde", "serde_json", - "toml 0.8.20", + "toml 0.8.19", "util", "wasm-encoder 0.221.3", "wasmparser 0.221.3", @@ -4577,7 +4598,7 @@ dependencies = [ "serde_json", "theme", "tokio", - "toml 0.8.20", + "toml 0.8.19", "tree-sitter", "wasmtime", ] @@ -4622,7 +4643,7 @@ dependencies = [ "tempfile", "theme", "theme_extension", - "toml 0.8.20", + "toml 0.8.19", "url", "util", "wasmparser 0.221.3", @@ -4824,9 +4845,9 @@ dependencies = [ [[package]] name = "filedescriptor" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" +checksum = "7199d965852c3bac31f779ef99cbb4537f80e952e2d6aa0ffeb30cce00f4f46e" dependencies = [ "libc", "thiserror 1.0.69", @@ -5505,9 +5526,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.16" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", @@ -6573,9 +6594,9 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.6" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "infer" @@ -6906,11 +6927,11 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "9.3.1" +version = "9.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" dependencies = [ - "base64 0.22.1", + "base64 0.21.7", "js-sys", "pem", "ring", @@ -7245,7 +7266,7 @@ dependencies = [ "task", "text", "theme", - "toml 0.8.20", + "toml 0.8.19", "tree-sitter", "tree-sitter-bash", "tree-sitter-c", @@ -7298,9 +7319,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.170" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libdbus-sys" @@ -7340,7 +7361,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -7436,18 +7457,18 @@ dependencies = [ [[package]] name = "linkme" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22d227772b5999ddc0690e733f734f95ca05387e329c4084fe65678c51198ffe" +checksum = "566336154b9e58a4f055f6dd4cbab62c7dc0826ce3c0a04e63b2d2ecd784cdae" dependencies = [ "linkme-impl", ] [[package]] name = "linkme-impl" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71a98813fa0073a317ed6a8055dcd4722a49d9b862af828ee68449adb799b6be" +checksum = "edbe595006d355eaf9ae11db92707d4338cd2384d16866131cc1afdbdd35d8d9" dependencies = [ "proc-macro2", "quote", @@ -7644,9 +7665,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.26" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" dependencies = [ "serde", "value-bag", @@ -7927,9 +7948,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.45" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07d36d96ffe1b5b16ddf2bc80b3b26bb7a498b2a6591061250bf0af8e8095ad" +checksum = "f9da1e54401fe5d45a664c57e112e70f18e8c5a73e268c179305b932ee864574" dependencies = [ "ammonia", "anyhow", @@ -8149,7 +8170,7 @@ dependencies = [ "mlua-sys", "num-traits", "parking_lot", - "rustc-hash 2.1.1", + "rustc-hash 2.1.0", ] [[package]] @@ -8933,9 +8954,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oo7" @@ -9016,9 +9037,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.70" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.8.0", "cfg-if", @@ -9057,9 +9078,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.105" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -9730,7 +9751,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "toml 0.8.20", + "toml 0.8.19", ] [[package]] @@ -10342,7 +10363,7 @@ dependencies = [ "tempfile", "terminal", "text", - "toml 0.8.20", + "toml 0.8.19", "unindent", "url", "util", @@ -10518,7 +10539,7 @@ checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes 1.10.1", "heck 0.5.0", - "itertools 0.10.5", + "itertools 0.12.1", "log", "multimap 0.10.0", "once_cell", @@ -10551,7 +10572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.90", @@ -10689,9 +10710,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.37.2" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" dependencies = [ "memchr", ] @@ -10706,7 +10727,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.1", + "rustc-hash 2.1.0", "rustls 0.23.23", "socket2", "thiserror 2.0.6", @@ -10724,7 +10745,7 @@ dependencies = [ "getrandom 0.2.15", "rand 0.8.5", "ring", - "rustc-hash 2.1.1", + "rustc-hash 2.1.0", "rustls 0.23.23", "rustls-pki-types", "slab", @@ -10736,9 +10757,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.9" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" dependencies = [ "cfg_aliases 0.2.1", "libc", @@ -10794,8 +10815,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.0", - "zerocopy 0.8.18", + "rand_core 0.9.3", + "zerocopy 0.8.23", ] [[package]] @@ -10825,7 +10846,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -10848,12 +10869,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom 0.3.1", - "zerocopy 0.8.18", ] [[package]] @@ -11051,7 +11071,7 @@ dependencies = [ "bumpalo", "hashbrown 0.15.2", "log", - "rustc-hash 2.1.1", + "rustc-hash 2.1.0", "smallvec", ] @@ -11185,7 +11205,7 @@ dependencies = [ "smol", "sysinfo", "telemetry_events", - "toml 0.8.20", + "toml 0.8.19", "unindent", "util", "worktree", @@ -11642,9 +11662,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc_version" @@ -11982,9 +12002,9 @@ dependencies = [ [[package]] name = "sea-orm" -version = "1.1.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00733e5418e8ae3758cdb988c3654174e716230cc53ee2cb884207cf86a23029" +checksum = "1a93194430b419da0801f404baf3b986399d6a2a4f43bc79bc96dea83f92ca43" dependencies = [ "async-stream", "async-trait", @@ -12010,9 +12030,9 @@ dependencies = [ [[package]] name = "sea-orm-macros" -version = "1.1.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98408f82fb4875d41ef469a79944a7da29767c7b3e4028e22188a3dd613b10f" +checksum = "d19e8f22fb474a8a622eb516c46885a080535d8d559386188f525977eaad32b3" dependencies = [ "heck 0.4.1", "proc-macro2", @@ -12205,18 +12225,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.218" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.218" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -12245,9 +12265,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.139" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "indexmap", "itoa", @@ -12596,9 +12616,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" dependencies = [ "serde", ] @@ -13425,7 +13445,7 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.20", + "toml 0.8.19", "version-compare", ] @@ -13572,9 +13592,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.17.1" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" dependencies = [ "cfg-if", "fastrand 2.3.0", @@ -14158,9 +14178,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", @@ -14179,15 +14199,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.23" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.7.1", + "winnow 0.6.20", ] [[package]] @@ -14429,9 +14449,9 @@ dependencies = [ [[package]] name = "tree-sitter-elixir" -version = "0.3.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e45d444647b4fd53d8fd32474c1b8bedc1baa22669ce3a78d083e365fa9a2d3f" +checksum = "23d7310aea06158653d18959123a64262bfbf122b7437899dea0c338654a51d3" dependencies = [ "cc", "tree-sitter-language", @@ -14934,11 +14954,11 @@ dependencies = [ [[package]] name = "uuid" -version = "1.13.2" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.2.15", "serde", "sha1_smol", ] @@ -15640,9 +15660,9 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.8" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" dependencies = [ "cc", "downcast-rs", @@ -15654,9 +15674,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.8" +version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" +checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" dependencies = [ "bitflags 2.8.0", "rustix", @@ -15666,9 +15686,9 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.31.8" +version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" +checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c" dependencies = [ "rustix", "wayland-client", @@ -15702,20 +15722,20 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.6" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" dependencies = [ "proc-macro2", - "quick-xml 0.37.2", + "quick-xml 0.36.2", "quote", ] [[package]] name = "wayland-sys" -version = "0.31.6" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" dependencies = [ "dlib", "log", @@ -15928,7 +15948,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -16438,9 +16458,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e376c75f4f43f44db463cf729e0d3acbf954d13e22c51e26e4c264b4ab545f" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" dependencies = [ "memchr", ] @@ -16471,7 +16491,7 @@ version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7276691b353ad4547af8c3268488d1311f4be791ffdc0c65b8cfa8f41eed693b" dependencies = [ - "toml 0.8.20", + "toml 0.8.19", "version_check", ] @@ -16973,7 +16993,7 @@ dependencies = [ "tracing", "uds_windows", "windows-sys 0.59.0", - "winnow 0.7.1", + "winnow 0.7.4", "xdg-home", "zbus_macros", "zbus_names", @@ -17251,11 +17271,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.18" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79386d31a42a4996e3336b0919ddb90f81112af416270cff95b5f5af22b839c2" +checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" dependencies = [ - "zerocopy-derive 0.8.18", + "zerocopy-derive 0.8.23", ] [[package]] @@ -17271,9 +17291,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.18" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76331675d372f91bf8d17e13afbd5fe639200b73d01f0fc748bb059f9cca2db7" +checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" dependencies = [ "proc-macro2", "quote", @@ -17505,7 +17525,7 @@ dependencies = [ "serde", "static_assertions", "url", - "winnow 0.7.1", + "winnow 0.7.4", "zvariant_derive", "zvariant_utils", ] @@ -17534,5 +17554,5 @@ dependencies = [ "serde", "static_assertions", "syn 2.0.90", - "winnow 0.7.1", + "winnow 0.7.4", ] diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 71df22e95d..3d339d02de 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -32,12 +32,12 @@ use util::ResultExt; use crate::{ current_platform, hash, init_app_menus, Action, ActionBuildError, ActionRegistry, Any, AnyView, AnyWindowHandle, AppContext, Asset, AssetSource, BackgroundExecutor, Bounds, ClipboardItem, - DispatchPhase, DisplayId, EventEmitter, FocusHandle, FocusMap, ForegroundExecutor, Global, - KeyBinding, Keymap, Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, - Platform, PlatformDisplay, Point, PromptBuilder, PromptHandle, PromptLevel, Render, - RenderablePromptHandle, Reservation, ScreenCaptureSource, SharedString, SubscriberSet, - Subscription, SvgRenderer, Task, TextSystem, Window, WindowAppearance, WindowHandle, WindowId, - WindowInvalidator, + DispatchPhase, DisplayId, EventEmitter, FocusHandle, FocusMap, ForegroundContext, + ForegroundExecutor, Global, KeyBinding, Keymap, Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, + PathPromptOptions, Pixels, Platform, PlatformDisplay, Point, PromptBuilder, PromptHandle, + PromptLevel, Render, RenderablePromptHandle, Reservation, ScreenCaptureSource, SharedString, + SubscriberSet, Subscription, SvgRenderer, Task, TextSystem, Window, WindowAppearance, + WindowHandle, WindowId, WindowInvalidator, }; mod async_context; @@ -1054,7 +1054,9 @@ impl App { Fut: Future + 'static, R: 'static, { - self.foreground_executor.spawn(f(self.to_async())) + let async_app = self.to_async(); + self.foreground_executor + .spawn_with_context(ForegroundContext::app(&async_app.app), f(async_app)) } /// Schedules the given function to be run at the end of the current effect cycle, allowing entities @@ -1596,8 +1598,6 @@ impl App { } impl AppContext for App { - type Result = T; - /// Build an entity that is owned by the application. The given function will be invoked with /// a `Context` and must return an object representing the entity. A `Entity` handle will be returned, /// which can be used to access the entity in a context. @@ -1621,7 +1621,7 @@ impl AppContext for App { }) } - fn reserve_entity(&mut self) -> Self::Result> { + fn reserve_entity(&mut self) -> Reservation { Reservation(self.entities.reserve()) } @@ -1629,7 +1629,7 @@ impl AppContext for App { &mut self, reservation: Reservation, build_entity: impl FnOnce(&mut Context<'_, T>) -> T, - ) -> Self::Result> { + ) -> Entity { self.update(|cx| { let slot = reservation.0; let entity = build_entity(&mut Context::new_context(cx, slot.downgrade())); @@ -1655,11 +1655,7 @@ impl AppContext for App { }) } - fn read_entity( - &self, - handle: &Entity, - read: impl FnOnce(&T, &App) -> R, - ) -> Self::Result + fn read_entity(&self, handle: &Entity, read: impl FnOnce(&T, &App) -> R) -> R where T: 'static, { @@ -1704,7 +1700,7 @@ impl AppContext for App { self.background_executor.spawn(future) } - fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result + fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> R where G: Global, { diff --git a/crates/gpui/src/app/async_context.rs b/crates/gpui/src/app/async_context.rs index 2f8347dbe0..9dca7ce686 100644 --- a/crates/gpui/src/app/async_context.rs +++ b/crates/gpui/src/app/async_context.rs @@ -1,9 +1,9 @@ use crate::{ AnyView, AnyWindowHandle, App, AppCell, AppContext, BackgroundExecutor, BorrowAppContext, - Entity, Focusable, ForegroundExecutor, Global, PromptLevel, Render, Reservation, Result, Task, - VisualContext, Window, WindowHandle, + Entity, Focusable, ForegroundContext, ForegroundExecutor, Global, PromptLevel, Render, + Reservation, Result, Task, VisualContext, Window, WindowHandle, }; -use anyhow::{anyhow, Context as _}; + use derive_more::{Deref, DerefMut}; use futures::channel::oneshot; use std::{future::Future, rc::Weak}; @@ -21,73 +21,55 @@ pub struct AsyncApp { } impl AppContext for AsyncApp { - type Result = Result; - fn new( &mut self, build_entity: impl FnOnce(&mut Context<'_, T>) -> T, - ) -> Self::Result> { - let app = self - .app - .upgrade() - .ok_or_else(|| anyhow!("app was released"))?; + ) -> Entity { + let app = self.app.upgrade().unwrap(); let mut app = app.borrow_mut(); - Ok(app.new(build_entity)) + app.new(build_entity) } - fn reserve_entity(&mut self) -> Result> { - let app = self - .app - .upgrade() - .ok_or_else(|| anyhow!("app was released"))?; + fn reserve_entity(&mut self) -> Reservation { + let app = self.app.upgrade().unwrap(); let mut app = app.borrow_mut(); - Ok(app.reserve_entity()) + app.reserve_entity() } fn insert_entity( &mut self, reservation: Reservation, build_entity: impl FnOnce(&mut Context<'_, T>) -> T, - ) -> Result> { - let app = self - .app - .upgrade() - .ok_or_else(|| anyhow!("app was released"))?; + ) -> Entity { + let app = self.app.upgrade().unwrap(); let mut app = app.borrow_mut(); - Ok(app.insert_entity(reservation, build_entity)) + app.insert_entity(reservation, build_entity) } fn update_entity( &mut self, handle: &Entity, update: impl FnOnce(&mut T, &mut Context<'_, T>) -> R, - ) -> Self::Result { - let app = self - .app - .upgrade() - .ok_or_else(|| anyhow!("app was released"))?; + ) -> R { + let app = self.app.upgrade().unwrap(); let mut app = app.borrow_mut(); - Ok(app.update_entity(handle, update)) + app.update_entity(handle, update) } - fn read_entity( - &self, - handle: &Entity, - callback: impl FnOnce(&T, &App) -> R, - ) -> Self::Result + fn read_entity(&self, handle: &Entity, callback: impl FnOnce(&T, &App) -> R) -> R where T: 'static, { - let app = self.app.upgrade().context("app was released")?; + let app = self.app.upgrade().unwrap(); let lock = app.borrow(); - Ok(lock.read_entity(handle, callback)) + lock.read_entity(handle, callback) } fn update_window(&mut self, window: AnyWindowHandle, f: F) -> Result where F: FnOnce(AnyView, &mut Window, &mut App) -> T, { - let app = self.app.upgrade().context("app was released")?; + let app = self.app.upgrade().unwrap(); let mut lock = app.borrow_mut(); lock.update_window(window, f) } @@ -100,7 +82,7 @@ impl AppContext for AsyncApp { where T: 'static, { - let app = self.app.upgrade().context("app was released")?; + let app = self.app.upgrade().unwrap(); let lock = app.borrow(); lock.read_window(window, read) } @@ -112,23 +94,20 @@ impl AppContext for AsyncApp { self.background_executor.spawn(future) } - fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result + fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> R where G: Global, { - let app = self.app.upgrade().context("app was released")?; + let app = self.app.upgrade().unwrap(); let mut lock = app.borrow_mut(); - Ok(lock.update(|this| this.read_global(callback))) + lock.update(|this| this.read_global(callback)) } } impl AsyncApp { /// Schedules all windows in the application to be redrawn. pub fn refresh(&self) -> Result<()> { - let app = self - .app - .upgrade() - .ok_or_else(|| anyhow!("app was released"))?; + let app = self.app.upgrade().unwrap(); let mut lock = app.borrow_mut(); lock.refresh_windows(); Ok(()) @@ -146,10 +125,7 @@ impl AsyncApp { /// Invoke the given function in the context of the app, then flush any effects produced during its invocation. pub fn update(&self, f: impl FnOnce(&mut App) -> R) -> Result { - let app = self - .app - .upgrade() - .ok_or_else(|| anyhow!("app was released"))?; + let app = self.app.upgrade().unwrap(); let mut lock = app.borrow_mut(); Ok(lock.update(f)) } @@ -163,10 +139,7 @@ impl AsyncApp { where V: 'static + Render, { - let app = self - .app - .upgrade() - .ok_or_else(|| anyhow!("app was released"))?; + let app = self.app.upgrade().unwrap(); let mut lock = app.borrow_mut(); lock.open_window(options, build_root_view) } @@ -178,31 +151,26 @@ impl AsyncApp { Fut: Future + 'static, R: 'static, { - self.foreground_executor.spawn(f(self.clone())) + self.foreground_executor + .spawn_with_context(ForegroundContext::app(&self.app), f(self.clone())) } /// Determine whether global state of the specified type has been assigned. /// Returns an error if the `App` has been dropped. - pub fn has_global(&self) -> Result { - let app = self - .app - .upgrade() - .ok_or_else(|| anyhow!("app was released"))?; + pub fn has_global(&self) -> bool { + let app = self.app.upgrade().unwrap(); let app = app.borrow_mut(); - Ok(app.has_global::()) + app.has_global::() } /// Reads the global state of the specified type, passing it to the given callback. /// /// Panics if no global state of the specified type has been assigned. /// Returns an error if the `App` has been dropped. - pub fn read_global(&self, read: impl FnOnce(&G, &App) -> R) -> Result { - let app = self - .app - .upgrade() - .ok_or_else(|| anyhow!("app was released"))?; + pub fn read_global(&self, read: impl FnOnce(&G, &App) -> R) -> R { + let app = self.app.upgrade().unwrap(); let app = app.borrow_mut(); - Ok(read(app.global(), &app)) + read(app.global(), &app) } /// Reads the global state of the specified type, passing it to the given callback. @@ -223,10 +191,7 @@ impl AsyncApp { &self, update: impl FnOnce(&mut G, &mut App) -> R, ) -> Result { - let app = self - .app - .upgrade() - .ok_or_else(|| anyhow!("app was released"))?; + let app = self.app.upgrade().unwrap(); let mut app = app.borrow_mut(); Ok(app.update(|cx| cx.update_global(update))) } @@ -304,7 +269,10 @@ impl AsyncWindowContext { Fut: Future + 'static, R: 'static, { - self.foreground_executor.spawn(f(self.clone())) + self.foreground_executor.spawn_with_context( + ForegroundContext::window(&self.app.app, self.window.id), + f(self.clone()), + ) } /// Present a platform dialog. @@ -326,42 +294,42 @@ impl AsyncWindowContext { } impl AppContext for AsyncWindowContext { - type Result = Result; - - fn new(&mut self, build_entity: impl FnOnce(&mut Context<'_, T>) -> T) -> Result> + fn new(&mut self, build_entity: impl FnOnce(&mut Context<'_, T>) -> T) -> Entity where T: 'static, { - self.window.update(self, |_, _, cx| cx.new(build_entity)) + self.window + .update(self, |_, _, cx| cx.new(build_entity)) + .unwrap() } - fn reserve_entity(&mut self) -> Result> { - self.window.update(self, |_, _, cx| cx.reserve_entity()) + fn reserve_entity(&mut self) -> Reservation { + self.window + .update(self, |_, _, cx| cx.reserve_entity()) + .unwrap() } fn insert_entity( &mut self, reservation: Reservation, build_entity: impl FnOnce(&mut Context<'_, T>) -> T, - ) -> Self::Result> { + ) -> Entity { self.window .update(self, |_, _, cx| cx.insert_entity(reservation, build_entity)) + .unwrap() } fn update_entity( &mut self, handle: &Entity, update: impl FnOnce(&mut T, &mut Context<'_, T>) -> R, - ) -> Result { + ) -> R { self.window .update(self, |_, _, cx| cx.update_entity(handle, update)) + .unwrap() } - fn read_entity( - &self, - handle: &Entity, - read: impl FnOnce(&T, &App) -> R, - ) -> Self::Result + fn read_entity(&self, handle: &Entity, read: impl FnOnce(&T, &App) -> R) -> R where T: 'static, { @@ -393,7 +361,7 @@ impl AppContext for AsyncWindowContext { self.app.background_executor.spawn(future) } - fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> Result + fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> R where G: Global, { @@ -409,38 +377,44 @@ impl VisualContext for AsyncWindowContext { fn new_window_entity( &mut self, build_entity: impl FnOnce(&mut Window, &mut Context) -> T, - ) -> Self::Result> { + ) -> Entity { self.window .update(self, |_, window, cx| cx.new(|cx| build_entity(window, cx))) + .unwrap() } fn update_window_entity( &mut self, view: &Entity, update: impl FnOnce(&mut T, &mut Window, &mut Context) -> R, - ) -> Self::Result { - self.window.update(self, |_, window, cx| { - view.update(cx, |entity, cx| update(entity, window, cx)) - }) + ) -> R { + self.window + .update(self, |_, window, cx| { + view.update(cx, |entity, cx| update(entity, window, cx)) + }) + .unwrap() } fn replace_root_view( &mut self, build_view: impl FnOnce(&mut Window, &mut Context) -> V, - ) -> Self::Result> + ) -> Entity where V: 'static + Render, { self.window .update(self, |_, window, cx| window.replace_root(cx, build_view)) + .unwrap() } - fn focus(&mut self, view: &Entity) -> Self::Result<()> + fn focus(&mut self, view: &Entity) where V: Focusable, { - self.window.update(self, |_, window, cx| { - view.read(cx).focus_handle(cx).clone().focus(window); - }) + self.window + .update(self, |_, window, cx| { + view.read(cx).focus_handle(cx).clone().focus(window); + }) + .unwrap() } } diff --git a/crates/gpui/src/app/context.rs b/crates/gpui/src/app/context.rs index 526a116b6c..b184fff1c1 100644 --- a/crates/gpui/src/app/context.rs +++ b/crates/gpui/src/app/context.rs @@ -679,9 +679,7 @@ impl Context<'_, T> { } } -impl AppContext for Context<'_, T> { - type Result = U; - +impl AppContext for Context { fn new( &mut self, build_entity: impl FnOnce(&mut Context<'_, U>) -> U, @@ -697,7 +695,7 @@ impl AppContext for Context<'_, T> { &mut self, reservation: Reservation, build_entity: impl FnOnce(&mut Context<'_, U>) -> U, - ) -> Self::Result> { + ) -> Entity { self.app.insert_entity(reservation, build_entity) } @@ -709,11 +707,7 @@ impl AppContext for Context<'_, T> { self.app.update_entity(handle, update) } - fn read_entity( - &self, - handle: &Entity, - read: impl FnOnce(&U, &App) -> R, - ) -> Self::Result + fn read_entity(&self, handle: &Entity, read: impl FnOnce(&U, &App) -> R) -> R where U: 'static, { @@ -745,7 +739,7 @@ impl AppContext for Context<'_, T> { self.app.background_executor.spawn(future) } - fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result + fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> R where G: Global, { diff --git a/crates/gpui/src/app/entity_map.rs b/crates/gpui/src/app/entity_map.rs index 60b59079a9..60e4f00541 100644 --- a/crates/gpui/src/app/entity_map.rs +++ b/crates/gpui/src/app/entity_map.rs @@ -418,11 +418,7 @@ impl Entity { } /// Read the entity referenced by this handle with the given function. - pub fn read_with( - &self, - cx: &C, - f: impl FnOnce(&T, &App) -> R, - ) -> C::Result { + pub fn read_with(&self, cx: &C, f: impl FnOnce(&T, &App) -> R) -> R { cx.read_entity(self, f) } @@ -435,7 +431,7 @@ impl Entity { &self, cx: &mut C, update: impl FnOnce(&mut T, &mut Context<'_, T>) -> R, - ) -> C::Result + ) -> R where C: AppContext, { @@ -449,7 +445,7 @@ impl Entity { &self, cx: &mut C, update: impl FnOnce(&mut T, &mut Window, &mut Context<'_, T>) -> R, - ) -> C::Result + ) -> R where C: VisualContext, { @@ -646,13 +642,10 @@ impl WeakEntity { ) -> Result where C: AppContext, - Result>: crate::Flatten, { - crate::Flatten::flatten( - self.upgrade() - .ok_or_else(|| anyhow!("entity released")) - .map(|this| cx.update_entity(&this, update)), - ) + self.upgrade() + .ok_or_else(|| anyhow!("entity released")) + .map(|this| cx.update_entity(&this, update)) } /// Updates the entity referenced by this handle with the given function if @@ -665,14 +658,13 @@ impl WeakEntity { ) -> Result where C: VisualContext, - Result>: crate::Flatten, { let window = cx.window_handle(); let this = self.upgrade().ok_or_else(|| anyhow!("entity released"))?; - crate::Flatten::flatten(window.update(cx, |_, window, cx| { + window.update(cx, |_, window, cx| { this.update(cx, |entity, cx| update(entity, window, cx)) - })) + }) } /// Reads the entity referenced by this handle with the given function if @@ -681,13 +673,10 @@ impl WeakEntity { pub fn read_with(&self, cx: &C, read: impl FnOnce(&T, &App) -> R) -> Result where C: AppContext, - Result>: crate::Flatten, { - crate::Flatten::flatten( - self.upgrade() - .ok_or_else(|| anyhow!("entity release")) - .map(|this| cx.read_entity(&this, read)), - ) + self.upgrade() + .ok_or_else(|| anyhow!("entity release")) + .map(|this| cx.read_entity(&this, read)) } } diff --git a/crates/gpui/src/app/test_context.rs b/crates/gpui/src/app/test_context.rs index c4cb595252..3424ad5810 100644 --- a/crates/gpui/src/app/test_context.rs +++ b/crates/gpui/src/app/test_context.rs @@ -1,9 +1,9 @@ use crate::{ Action, AnyView, AnyWindowHandle, App, AppCell, AppContext, AsyncApp, AvailableSpace, BackgroundExecutor, BorrowAppContext, Bounds, ClipboardItem, DrawPhase, Drawable, Element, - Empty, EventEmitter, ForegroundExecutor, Global, InputEvent, Keystroke, Modifiers, - ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, - Platform, Point, Render, Result, Size, Task, TestDispatcher, TestPlatform, + Empty, EventEmitter, ForegroundContext, ForegroundExecutor, Global, InputEvent, Keystroke, + Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, + Pixels, Platform, Point, Render, Result, Size, Task, TestDispatcher, TestPlatform, TestScreenCaptureSource, TestWindow, TextSystem, VisualContext, Window, WindowBounds, WindowHandle, WindowOptions, }; @@ -30,17 +30,15 @@ pub struct TestAppContext { } impl AppContext for TestAppContext { - type Result = T; - fn new( &mut self, build_entity: impl FnOnce(&mut Context<'_, T>) -> T, - ) -> Self::Result> { + ) -> Entity { let mut app = self.app.borrow_mut(); app.new(build_entity) } - fn reserve_entity(&mut self) -> Self::Result> { + fn reserve_entity(&mut self) -> crate::Reservation { let mut app = self.app.borrow_mut(); app.reserve_entity() } @@ -49,7 +47,7 @@ impl AppContext for TestAppContext { &mut self, reservation: crate::Reservation, build_entity: impl FnOnce(&mut Context<'_, T>) -> T, - ) -> Self::Result> { + ) -> Entity { let mut app = self.app.borrow_mut(); app.insert_entity(reservation, build_entity) } @@ -58,16 +56,12 @@ impl AppContext for TestAppContext { &mut self, handle: &Entity, update: impl FnOnce(&mut T, &mut Context<'_, T>) -> R, - ) -> Self::Result { + ) -> R { let mut app = self.app.borrow_mut(); app.update_entity(handle, update) } - fn read_entity( - &self, - handle: &Entity, - read: impl FnOnce(&T, &App) -> R, - ) -> Self::Result + fn read_entity(&self, handle: &Entity, read: impl FnOnce(&T, &App) -> R) -> R where T: 'static, { @@ -102,7 +96,7 @@ impl AppContext for TestAppContext { self.background_executor.spawn(future) } - fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result + fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> R where G: Global, { @@ -329,7 +323,10 @@ impl TestAppContext { Fut: Future + 'static, R: 'static, { - self.foreground_executor.spawn(f(self.to_async())) + self.foreground_executor.spawn_with_context( + ForegroundContext::app(&Rc::downgrade(&self.app)), + f(self.to_async()), + ) } /// true if the given global is defined @@ -868,16 +865,14 @@ impl VisualTestContext { } impl AppContext for VisualTestContext { - type Result = ::Result; - fn new( &mut self, build_entity: impl FnOnce(&mut Context<'_, T>) -> T, - ) -> Self::Result> { + ) -> Entity { self.cx.new(build_entity) } - fn reserve_entity(&mut self) -> Self::Result> { + fn reserve_entity(&mut self) -> crate::Reservation { self.cx.reserve_entity() } @@ -885,7 +880,7 @@ impl AppContext for VisualTestContext { &mut self, reservation: crate::Reservation, build_entity: impl FnOnce(&mut Context<'_, T>) -> T, - ) -> Self::Result> { + ) -> Entity { self.cx.insert_entity(reservation, build_entity) } @@ -893,18 +888,14 @@ impl AppContext for VisualTestContext { &mut self, handle: &Entity, update: impl FnOnce(&mut T, &mut Context<'_, T>) -> R, - ) -> Self::Result + ) -> R where T: 'static, { self.cx.update_entity(handle, update) } - fn read_entity( - &self, - handle: &Entity, - read: impl FnOnce(&T, &App) -> R, - ) -> Self::Result + fn read_entity(&self, handle: &Entity, read: impl FnOnce(&T, &App) -> R) -> R where T: 'static, { @@ -936,7 +927,7 @@ impl AppContext for VisualTestContext { self.cx.background_spawn(future) } - fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result + fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> R where G: Global, { @@ -953,7 +944,7 @@ impl VisualContext for VisualTestContext { fn new_window_entity( &mut self, build_entity: impl FnOnce(&mut Window, &mut Context<'_, T>) -> T, - ) -> Self::Result> { + ) -> Entity { self.window .update(&mut self.cx, |_, window, cx| { cx.new(|cx| build_entity(window, cx)) @@ -965,7 +956,7 @@ impl VisualContext for VisualTestContext { &mut self, view: &Entity, update: impl FnOnce(&mut V, &mut Window, &mut Context) -> R, - ) -> Self::Result { + ) -> R { self.window .update(&mut self.cx, |_, window, cx| { view.update(cx, |v, cx| update(v, window, cx)) @@ -976,7 +967,7 @@ impl VisualContext for VisualTestContext { fn replace_root_view( &mut self, build_view: impl FnOnce(&mut Window, &mut Context) -> V, - ) -> Self::Result> + ) -> Entity where V: 'static + Render, { @@ -987,7 +978,7 @@ impl VisualContext for VisualTestContext { .unwrap() } - fn focus(&mut self, view: &Entity) -> Self::Result<()> { + fn focus(&mut self, view: &Entity) { self.window .update(&mut self.cx, |_, window, cx| { view.read(cx).focus_handle(cx).clone().focus(window) diff --git a/crates/gpui/src/executor.rs b/crates/gpui/src/executor.rs index 4f78f97ad3..eb4968882f 100644 --- a/crates/gpui/src/executor.rs +++ b/crates/gpui/src/executor.rs @@ -1,10 +1,7 @@ -use crate::{App, PlatformDispatcher}; -use async_task::Runnable; +use crate::{App, ForegroundContext, PlatformDispatcher}; +use async_task::Builder; use futures::channel::mpsc; use smol::prelude::*; -use std::mem::ManuallyDrop; -use std::panic::Location; -use std::thread::{self, ThreadId}; use std::{ fmt::Debug, marker::PhantomData, @@ -17,6 +14,7 @@ use std::{ Arc, }, task::{Context, Poll}, + thread::ThreadId, time::{Duration, Instant}, }; use util::TryFutureExt; @@ -44,6 +42,7 @@ pub struct BackgroundExecutor { pub struct ForegroundExecutor { #[doc(hidden)] pub dispatcher: Arc, + not_send: PhantomData>, } @@ -64,6 +63,9 @@ enum TaskState { /// A task that is currently running. Spawned(async_task::Task), + + /// A task that is currently running on the foreground + SpawnedOnForeground(async_task::Task), } impl Task { @@ -77,6 +79,7 @@ impl Task { match self { Task(TaskState::Ready(_)) => {} Task(TaskState::Spawned(task)) => task.detach(), + Task(TaskState::SpawnedOnForeground(task)) => task.detach(), } } } @@ -92,7 +95,7 @@ where pub fn detach_and_log_err(self, cx: &App) { let location = core::panic::Location::caller(); cx.foreground_executor() - .spawn(self.log_tracked_err(*location)) + .spawn_with_context(ForegroundContext::none(), self.log_tracked_err(*location)) .detach(); } } @@ -104,6 +107,7 @@ impl Future for Task { match unsafe { self.get_unchecked_mut() } { Task(TaskState::Ready(val)) => Poll::Ready(val.take().unwrap()), Task(TaskState::Spawned(task)) => task.poll(cx), + Task(TaskState::SpawnedOnForeground(task)) => task.poll(cx), } } } @@ -127,8 +131,6 @@ impl TaskLabel { } } -type AnyLocalFuture = Pin>>; - type AnyFuture = Pin>>; /// BackgroundExecutor lets you run things on background threads. @@ -441,6 +443,17 @@ impl BackgroundExecutor { } } +/// std::thread::current() doesn't always reliably return the same ID. +/// This does. +#[inline] +pub(crate) fn thread_id() -> ThreadId { + std::thread_local! { + static ID: ThreadId = std::thread::current().id(); + } + ID.try_with(|id| *id) + .unwrap_or_else(|_| std::thread::current().id()) +} + /// ForegroundExecutor runs things on the main thread. impl ForegroundExecutor { /// Creates a new ForegroundExecutor from the given PlatformDispatcher. @@ -457,88 +470,31 @@ impl ForegroundExecutor { where R: 'static, { + self.spawn_with_context(ForegroundContext::none(), future) + } + + /// Enqueues the given Task to run on the main thread at some point in the future, + /// with a context parameter that will be checked before each turn + pub fn spawn_with_context( + &self, + mut context: ForegroundContext, + future: impl Future + 'static, + ) -> Task + where + R: 'static, + { + context.spawning_thread = Some(thread_id()); let dispatcher = self.dispatcher.clone(); - #[track_caller] - fn inner( - dispatcher: Arc, - future: AnyLocalFuture, - ) -> Task { - let (runnable, task) = spawn_local_with_source_location(future, move |runnable| { - dispatcher.dispatch_on_main_thread(runnable) - }); - runnable.schedule(); - Task(TaskState::Spawned(task)) - } - inner::(dispatcher, Box::pin(future)) + let (runnable, task) = Builder::new().metadata(context).spawn_local( + |_| future, + move |runnable| dispatcher.dispatch_on_main_thread(runnable), + ); + runnable.schedule(); + Task(TaskState::SpawnedOnForeground(task)) } } -/// Variant of `async_task::spawn_local` that includes the source location of the spawn in panics. -/// -/// Copy-modified from: -/// https://github.com/smol-rs/async-task/blob/ca9dbe1db9c422fd765847fa91306e30a6bb58a9/src/runnable.rs#L405 -#[track_caller] -fn spawn_local_with_source_location( - future: Fut, - schedule: S, -) -> (Runnable<()>, async_task::Task) -where - Fut: Future + 'static, - Fut::Output: 'static, - S: async_task::Schedule<()> + Send + Sync + 'static, -{ - #[inline] - fn thread_id() -> ThreadId { - std::thread_local! { - static ID: ThreadId = thread::current().id(); - } - ID.try_with(|id| *id) - .unwrap_or_else(|_| thread::current().id()) - } - - struct Checked { - id: ThreadId, - inner: ManuallyDrop, - location: &'static Location<'static>, - } - - impl Drop for Checked { - fn drop(&mut self) { - assert!( - self.id == thread_id(), - "local task dropped by a thread that didn't spawn it. Task spawned at {}", - self.location - ); - unsafe { - ManuallyDrop::drop(&mut self.inner); - } - } - } - - impl Future for Checked { - type Output = F::Output; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - assert!( - self.id == thread_id(), - "local task polled by a thread that didn't spawn it. Task spawned at {}", - self.location - ); - unsafe { self.map_unchecked_mut(|c| &mut *c.inner).poll(cx) } - } - } - - // Wrap the future into one that checks which thread it's on. - let future = Checked { - id: thread_id(), - inner: ManuallyDrop::new(future), - location: Location::caller(), - }; - - unsafe { async_task::spawn_unchecked(future, schedule) } -} - /// Scope manages a set of tasks that are enqueued and waited on together. See [`BackgroundExecutor::scoped`]. pub struct Scope<'a> { executor: BackgroundExecutor, diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 1ebfc643ee..ea6e0bcc58 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -161,19 +161,13 @@ use taffy::TaffyLayoutEngine; /// The context trait, allows the different contexts in GPUI to be used /// interchangeably for certain operations. pub trait AppContext { - /// The result type for this context, used for async contexts that - /// can't hold a direct reference to the application context. - type Result; - /// Create a new entity in the app context. - fn new( - &mut self, - build_entity: impl FnOnce(&mut Context<'_, T>) -> T, - ) -> Self::Result>; + fn new(&mut self, build_entity: impl FnOnce(&mut Context<'_, T>) -> T) + -> Entity; /// Reserve a slot for a entity to be inserted later. /// The returned [Reservation] allows you to obtain the [EntityId] for the future entity. - fn reserve_entity(&mut self) -> Self::Result>; + fn reserve_entity(&mut self) -> Reservation; /// Insert a new entity in the app context based on a [Reservation] previously obtained from [`reserve_entity`]. /// @@ -182,23 +176,19 @@ pub trait AppContext { &mut self, reservation: Reservation, build_entity: impl FnOnce(&mut Context<'_, T>) -> T, - ) -> Self::Result>; + ) -> Entity; /// Update a entity in the app context. fn update_entity( &mut self, handle: &Entity, update: impl FnOnce(&mut T, &mut Context<'_, T>) -> R, - ) -> Self::Result + ) -> R where T: 'static; /// Read a entity from the app context. - fn read_entity( - &self, - handle: &Entity, - read: impl FnOnce(&T, &App) -> R, - ) -> Self::Result + fn read_entity(&self, handle: &Entity, read: impl FnOnce(&T, &App) -> R) -> R where T: 'static; @@ -222,7 +212,7 @@ pub trait AppContext { R: Send + 'static; /// Read a global from this app context - fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result + fn read_global(&self, callback: impl FnOnce(&G, &App) -> R) -> R where G: Global; } @@ -249,24 +239,24 @@ pub trait VisualContext: AppContext { &mut self, entity: &Entity, update: impl FnOnce(&mut T, &mut Window, &mut Context) -> R, - ) -> Self::Result; + ) -> R; /// Update a view with the given callback fn new_window_entity( &mut self, build_entity: impl FnOnce(&mut Window, &mut Context<'_, T>) -> T, - ) -> Self::Result>; + ) -> Entity; /// Replace the root view of a window with a new view. fn replace_root_view( &mut self, build_view: impl FnOnce(&mut Window, &mut Context) -> V, - ) -> Self::Result> + ) -> Entity where V: 'static + Render; /// Focus a entity in the window, if it implements the [`Focusable`] trait. - fn focus(&mut self, entity: &Entity) -> Self::Result<()> + fn focus(&mut self, entity: &Entity) where V: Focusable; } diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index ae89b5e172..e30b585ca9 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -27,11 +27,12 @@ mod test; mod windows; use crate::{ - point, Action, AnyWindowHandle, App, AsyncWindowContext, BackgroundExecutor, Bounds, - DevicePixels, DispatchEventResult, Font, FontId, FontMetrics, FontRun, ForegroundExecutor, - GlyphId, GpuSpecs, ImageSource, Keymap, LineLayout, Pixels, PlatformInput, Point, - RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, ScaledPixels, Scene, - SharedString, Size, SvgRenderer, SvgSize, Task, TaskLabel, Window, DEFAULT_WINDOW_SIZE, + point, thread_id, Action, AnyWindowHandle, App, AppCell, AsyncWindowContext, + BackgroundExecutor, Bounds, DevicePixels, DispatchEventResult, Font, FontId, FontMetrics, + FontRun, ForegroundExecutor, GlyphId, GpuSpecs, ImageSource, Keymap, LineLayout, Pixels, + PlatformInput, Point, RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, + ScaledPixels, Scene, SharedString, Size, SvgRenderer, SvgSize, Task, TaskLabel, Window, + WindowId, DEFAULT_WINDOW_SIZE, }; use anyhow::{anyhow, Result}; use async_task::Runnable; @@ -47,6 +48,9 @@ use std::borrow::Cow; use std::hash::{Hash, Hasher}; use std::io::Cursor; use std::ops; +use std::panic::Location; +use std::rc::Weak; +use std::thread::ThreadId; use std::time::{Duration, Instant}; use std::{ fmt::{self, Debug}, @@ -450,13 +454,104 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle { } } +#[derive(Debug)] +enum Contexts { + App { + app: Weak, + }, + Window { + app: Weak, + window: WindowId, + }, +} + +/// TODO +#[derive(Debug)] +pub struct ForegroundContext { + pub(crate) spawning_thread: Option, + location: &'static Location<'static>, + inner: Option, +} + +// SAFETY: Foreground context will safely panic before accessing non-thread safe data +unsafe impl Send for ForegroundContext {} +unsafe impl Sync for ForegroundContext {} + +impl ForegroundContext { + /// TODO + #[track_caller] + pub fn app(app: &Weak) -> Self { + Self::contexts(Some(Contexts::App { app: app.clone() })) + } + + /// TODO + #[track_caller] + pub fn window(app: &Weak, window: WindowId) -> Self { + Self::contexts(Some(Contexts::Window { + app: app.clone(), + window, + })) + } + + /// TODO + #[track_caller] + pub fn none() -> Self { + Self::contexts(None) + } + + #[track_caller] + fn contexts(contexts: Option) -> Self { + Self { + spawning_thread: None, + location: core::panic::Location::caller(), + inner: contexts, + } + } + + fn assert_thread_is_valid(&self) { + if let Some(spawning_thread) = self.spawning_thread { + assert!( + spawning_thread == thread_id(), + "local task polled by a thread that didn't spawn it. Task spawned at {}", + self.location + ); + } + } + + /// TODO + pub fn context_is_valid(&self) -> bool { + self.assert_thread_is_valid(); + + match &self.inner { + Some(Contexts::App { app }) => app.upgrade().is_some(), + Some(Contexts::Window { app, window }) => { + if let Some(app) = app.upgrade() { + let lock = app.borrow(); + let result = lock.windows.contains_key(*window); + drop(lock); + result + } else { + false + } + } + None => true, + } + } +} + +impl Drop for ForegroundContext { + fn drop(&mut self) { + self.assert_thread_is_valid(); + } +} + /// This type is public so that our test macro can generate and use it, but it should not /// be considered part of our public API. #[doc(hidden)] pub trait PlatformDispatcher: Send + Sync { fn is_main_thread(&self) -> bool; fn dispatch(&self, runnable: Runnable, label: Option); - fn dispatch_on_main_thread(&self, runnable: Runnable); + fn dispatch_on_main_thread(&self, runnable: Runnable); fn dispatch_after(&self, duration: Duration, runnable: Runnable); fn park(&self, timeout: Option) -> bool; fn unparker(&self) -> Unparker; diff --git a/crates/gpui/src/platform/mac/dispatcher.rs b/crates/gpui/src/platform/mac/dispatcher.rs index 13b2742d23..0b7b06532e 100644 --- a/crates/gpui/src/platform/mac/dispatcher.rs +++ b/crates/gpui/src/platform/mac/dispatcher.rs @@ -2,7 +2,7 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] -use crate::{PlatformDispatcher, TaskLabel}; +use crate::{ForegroundContext, PlatformDispatcher, TaskLabel}; use async_task::Runnable; use objc::{ class, msg_send, @@ -63,12 +63,12 @@ impl PlatformDispatcher for MacDispatcher { } } - fn dispatch_on_main_thread(&self, runnable: Runnable) { + fn dispatch_on_main_thread(&self, runnable: Runnable) { unsafe { dispatch_async_f( dispatch_get_main_queue(), runnable.into_raw().as_ptr() as *mut c_void, - Some(trampoline), + Some(context_trampoline), ); } } @@ -105,3 +105,14 @@ extern "C" fn trampoline(runnable: *mut c_void) { let task = unsafe { Runnable::<()>::from_raw(NonNull::new_unchecked(runnable as *mut ())) }; task.run(); } + +extern "C" fn context_trampoline(runnable: *mut c_void) { + let task = unsafe { + Runnable::::from_raw(NonNull::new_unchecked(runnable as *mut ())) + }; + if task.metadata().context_is_valid() { + task.run(); + } else { + drop(task); + } +} diff --git a/crates/gpui/src/platform/test/dispatcher.rs b/crates/gpui/src/platform/test/dispatcher.rs index 6319999293..086bde0719 100644 --- a/crates/gpui/src/platform/test/dispatcher.rs +++ b/crates/gpui/src/platform/test/dispatcher.rs @@ -1,4 +1,4 @@ -use crate::{PlatformDispatcher, TaskLabel}; +use crate::{platform::ForegroundContext, PlatformDispatcher, TaskLabel}; use async_task::Runnable; use backtrace::Backtrace; use collections::{HashMap, HashSet, VecDeque}; @@ -26,9 +26,13 @@ pub struct TestDispatcher { unparker: Unparker, } +// SAFETY: The test dispatcher is only ever run single threaded +unsafe impl Send for TestDispatcher {} +unsafe impl Sync for TestDispatcher {} + struct TestDispatcherState { random: StdRng, - foreground: HashMap>, + foreground: HashMap>>, background: Vec, deprioritized_background: Vec, delayed: Vec<(Duration, Runnable)>, @@ -135,7 +139,8 @@ impl TestDispatcher { }; let background_len = state.background.len(); - let runnable; + let mut background_runnable = None; + let mut foreground_runnable = None; let main_thread; if foreground_len == 0 && background_len == 0 { let deprioritized_background_len = state.deprioritized_background.len(); @@ -144,7 +149,7 @@ impl TestDispatcher { } let ix = state.random.gen_range(0..deprioritized_background_len); main_thread = false; - runnable = state.deprioritized_background.swap_remove(ix); + background_runnable = Some(state.deprioritized_background.swap_remove(ix)); } else { main_thread = state.random.gen_ratio( foreground_len as u32, @@ -152,24 +157,36 @@ impl TestDispatcher { ); if main_thread { let state = &mut *state; - runnable = state - .foreground - .values_mut() - .filter(|runnables| !runnables.is_empty()) - .choose(&mut state.random) - .unwrap() - .pop_front() - .unwrap(); + foreground_runnable = Some( + state + .foreground + .values_mut() + .filter(|runnables| !runnables.is_empty()) + .choose(&mut state.random) + .unwrap() + .pop_front() + .unwrap(), + ); } else { let ix = state.random.gen_range(0..background_len); - runnable = state.background.swap_remove(ix); + background_runnable = Some(state.background.swap_remove(ix)); }; }; let was_main_thread = state.is_main_thread; state.is_main_thread = main_thread; drop(state); - runnable.run(); + + if let Some(background_runnable) = background_runnable { + background_runnable.run(); + } else if let Some(foreground_runnable) = foreground_runnable { + if foreground_runnable.metadata().context_is_valid() { + foreground_runnable.run(); + } else { + drop(foreground_runnable); + } + } + self.state.lock().is_main_thread = was_main_thread; true @@ -272,7 +289,7 @@ impl PlatformDispatcher for TestDispatcher { self.unparker.unpark(); } - fn dispatch_on_main_thread(&self, runnable: Runnable) { + fn dispatch_on_main_thread(&self, runnable: Runnable) { self.state .lock() .foreground