Skip to content

Commit a18eb8a

Browse files
committed
more work
1 parent 20f3751 commit a18eb8a

9 files changed

Lines changed: 92 additions & 39 deletions

Cargo.lock

Lines changed: 0 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cot-cli/tests/snapshot_testing/new/snapshots/cli__snapshot_testing__new__create_new_project-5.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
---
22
source: cot-cli/tests/snapshot_testing/new/mod.rs
3+
assertion_line: 19
34
description: "Verbosity level: debug"
45
info:
56
program: cot
67
args:
78
- new
89
- "-vvvv"
9-
- /tmp/cot-test-o4uWVf/project
10+
- /tmp/cot-test-cGGhse/project
1011
---
1112
success: true
1213
exit_code: 0
1314
----- stdout -----
1415
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/Cargo.toml"
1516
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/Cargo.lock"
16-
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/bacon.toml"
1717
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/.gitignore"
1818
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/src/main.rs"
1919
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/src/migrations.rs"

cot-cli/tests/snapshot_testing/new/snapshots/cli__snapshot_testing__new__create_new_project-6.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
---
22
source: cot-cli/tests/snapshot_testing/new/mod.rs
3+
assertion_line: 19
34
description: "Verbosity level: trace"
45
info:
56
program: cot
67
args:
78
- new
89
- "-vvvvv"
9-
- /tmp/cot-test-QUOaBC/project
10+
- /tmp/cot-test-npgw5S/project
1011
---
1112
success: true
1213
exit_code: 0
1314
----- stdout -----
1415
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/Cargo.toml"
1516
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/Cargo.lock"
16-
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/bacon.toml"
1717
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/.gitignore"
1818
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/src/main.rs"
1919
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/src/migrations.rs"

cot-cli/tests/snapshot_testing/new/snapshots/cli__snapshot_testing__new__create_new_project_with_custom_name-5.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
source: cot-cli/tests/snapshot_testing/new/mod.rs
3+
assertion_line: 39
34
description: "Verbosity level: debug"
45
info:
56
program: cot
@@ -8,14 +9,13 @@ info:
89
- "--name"
910
- my_project
1011
- "-vvvv"
11-
- /tmp/cot-test-BEJYfS/project
12+
- /tmp/cot-test-3W8pnv/project
1213
---
1314
success: true
1415
exit_code: 0
1516
----- stdout -----
1617
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/Cargo.toml"
1718
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/Cargo.lock"
18-
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/bacon.toml"
1919
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/.gitignore"
2020
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/src/main.rs"
2121
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/src/migrations.rs"

cot-cli/tests/snapshot_testing/new/snapshots/cli__snapshot_testing__new__create_new_project_with_custom_name-6.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
source: cot-cli/tests/snapshot_testing/new/mod.rs
3+
assertion_line: 39
34
description: "Verbosity level: trace"
45
info:
56
program: cot
@@ -8,14 +9,13 @@ info:
89
- "--name"
910
- my_project
1011
- "-vvvvv"
11-
- /tmp/cot-test-IWoQbg/project
12+
- /tmp/cot-test-fHh4vf/project
1213
---
1314
success: true
1415
exit_code: 0
1516
----- stdout -----
1617
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/Cargo.toml"
1718
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/Cargo.lock"
18-
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/bacon.toml"
1919
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/.gitignore"
2020
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/src/main.rs"
2121
TIMESTAMP TRACE cot_cli::new_project: Writing file: "/tmp/TEMP_PATH/project/src/migrations.rs"

cot/Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ deadpool-redis = { workspace = true, features = ["tokio-comp", "rt_tokio_1"], op
3030
derive_builder.workspace = true
3131
derive_more = { workspace = true, features = ["debug", "deref", "display", "from"] }
3232
digest.workspace = true
33-
dioxus-devtools = { version = "0.7.2", features = ["serve"], optional = true }
33+
#dioxus-devtools = { version = "0.7.2", features = ["serve"], optional = true }
34+
dioxus-devtools = { path = "/home/m4tx/projects/dioxus/packages/devtools/", features = ["serve"], optional = true }
3435
email_address.workspace = true
3536
fake = { workspace = true, optional = true, features = ["derive", "chrono"] }
3637
form_urlencoded.workspace = true
@@ -58,7 +59,8 @@ serde_json = { workspace = true, optional = true }
5859
serde_path_to_error = { workspace = true }
5960
sha2.workspace = true
6061
sqlx = { workspace = true, features = ["runtime-tokio", "chrono"], optional = true }
61-
subsecond = { version = "0.7.2", optional = true }
62+
#subsecond = { version = "0.7.2", optional = true }
63+
subsecond = { path = "/home/m4tx/projects/dioxus/packages/subsecond/subsecond/", optional = true }
6264
subtle = { workspace = true, features = ["std"] }
6365
swagger-ui-redist = { workspace = true, optional = true }
6466
sync_wrapper.workspace = true

cot/src/handler.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ pub(crate) fn into_box_request_handler<T, H: RequestHandler<T> + Send + Sync>(
6666
request: Request,
6767
) -> Pin<Box<dyn Future<Output = Result<Response>> + Send + '_>> {
6868
Box::pin(crate::hot_patching::call_hot(
69-
|req| self.0.handle(req),
69+
|req| {
70+
Box::pin(self.0.handle(req))
71+
as Pin<Box<dyn Future<Output = Result<Response>> + Send>>
72+
},
7073
request,
7174
))
7275
}
@@ -81,8 +84,8 @@ macro_rules! impl_request_handler {
8184
where
8285
Func: FnOnce($($ty,)*) -> Fut + Clone + Send + Sync + 'static,
8386
$($ty: FromRequestHead + Send,)*
84-
Fut: Future<Output = R> + Send,
85-
R: IntoResponse,
87+
Fut: Future<Output = R> + Send + 'static,
88+
R: IntoResponse + 'static,
8689
{
8790
#[allow(
8891
clippy::allow_attributes,
@@ -101,8 +104,8 @@ macro_rules! impl_request_handler {
101104
let $ty = <$ty as FromRequestHead>::from_request_head(&head).await?;
102105
)*
103106

104-
$crate::__private::hot_patching::call_hot(
105-
move |($($ty,)*)| self.clone()($($ty,)*),
107+
$crate::__private::hot_patching::call_async(
108+
move |($($ty,)*)| Box::pin(self.clone()($($ty,)*)) as Pin<Box<dyn Future<Output = R> + Send>>,
106109
($($ty,)*),
107110
)
108111
.await
@@ -120,7 +123,7 @@ macro_rules! impl_request_handler_from_request {
120123
$($ty_lhs: FromRequestHead + Send,)*
121124
$ty_from_request: FromRequest + Send,
122125
$($ty_rhs: FromRequestHead + Send,)*
123-
Fut: Future<Output = R> + Send,
126+
Fut: Future<Output = R> + Send + 'static,
124127
R: IntoResponse,
125128
{
126129
#[allow(
@@ -144,7 +147,7 @@ macro_rules! impl_request_handler_from_request {
144147

145148
let $ty_from_request = $ty_from_request::from_request(&head, body).await?;
146149

147-
$crate::__private::hot_patching::call_hot(
150+
$crate::__private::hot_patching::call_async(
148151
move |($($ty_lhs,)* $ty_from_request, $($ty_rhs),*)| {
149152
self.clone()($($ty_lhs,)* $ty_from_request, $($ty_rhs),*)
150153
},

cot/src/hot_patching.rs

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
use std::panic::AssertUnwindSafe;
2+
use std::pin::Pin;
3+
4+
use subsecond::{HotFn, HotFnPanic};
5+
6+
/// Runs given future with [`subsecond`], dropping the future and re-running it
7+
/// when the code changes.
8+
///
9+
/// When the hot-patching feature is not enabled, the function just runs the
10+
/// future once.
111
#[allow(
212
clippy::allow_attributes,
313
reason = "Only happens when hot-patching is enabled"
@@ -6,14 +16,19 @@
616
clippy::future_not_send,
717
reason = "Send not needed; serve/Bootstrapper is run async in a single thread"
818
)]
9-
#[doc(hidden)]
1019
pub async fn serve<O, F>(callback: impl FnMut() -> F)
1120
where
1221
F: Future<Output = O> + 'static,
1322
{
23+
println!("1");
24+
1425
#[cfg(feature = "hot-patching")]
1526
{
16-
dioxus_devtools::serve_subsecond(callback).await;
27+
println!("2");
28+
// dioxus_devtools::serve_subsecond(callback).await;
29+
dioxus_devtools::connect_subsecond();
30+
let mut callback = callback;
31+
callback().await;
1732
}
1833

1934
#[cfg(not(feature = "hot-patching"))]
@@ -23,7 +38,10 @@ where
2338
}
2439
}
2540

26-
#[doc(hidden)]
41+
/// Calls the function using [`subsecond::HotFn`].
42+
///
43+
/// This causes the function passed to be hot-reloadable. If the hot-reloading
44+
/// feature is not enabled, the function is called directly.
2745
pub fn call_hot<F, A, R>(func: F, args: A) -> R
2846
where
2947
F: FnMut(A) -> R,
@@ -40,3 +58,51 @@ where
4058
func(args)
4159
}
4260
}
61+
62+
pub fn call_async<F, Fut, A, O>(f: F, args: A) -> Pin<Box<dyn Future<Output = O> + Send>>
63+
where
64+
F: FnOnce(A) -> Fut,
65+
Fut: Future<Output = O> + Send + 'static,
66+
{
67+
// return Box::pin(f(args));
68+
69+
// For FnOnce, we need to handle this differently since we can only call it once
70+
// We'll store the closure in an Option and take it when needed
71+
let mut f_option = Some(f);
72+
73+
// Create a wrapper function that boxes the future
74+
let wrapper = move |args| -> Pin<Box<dyn Future<Output = O> + Send>> {
75+
if let Some(closure) = f_option.take() {
76+
Box::pin(closure(args))
77+
} else {
78+
// This shouldn't happen in normal hot reload scenarios since each
79+
// hot reload creates a new call_async invocation
80+
panic!(
81+
"Hot reload closure already consumed - this indicates a problem with the hot reload system"
82+
)
83+
}
84+
};
85+
86+
let mut hotfn = HotFn::current(wrapper);
87+
loop {
88+
let res = std::panic::catch_unwind(AssertUnwindSafe(|| hotfn.call((args,))));
89+
90+
// If the call succeeds just return the result, otherwise we try to handle the
91+
// panic if its our own.
92+
let err = match res {
93+
Ok(res) => return res,
94+
Err(err) => err,
95+
};
96+
97+
// If this is our panic then let's handle it, otherwise we just resume unwinding
98+
let Some(_hot_payload) = err.downcast_ref::<HotFnPanic>() else {
99+
std::panic::resume_unwind(err);
100+
};
101+
102+
// For hot reload with FnOnce, we can't retry with the same closure
103+
// The hot reload system should create a new function call entirely
104+
panic!(
105+
"Hot reload detected but cannot retry with FnOnce closure - hot reload should create new function instance"
106+
);
107+
}
108+
}

cot/src/private.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,5 @@ pub use crate::utils::graph::apply_permutation;
2828
pub const COT_VERSION: &str = env!("CARGO_PKG_VERSION");
2929

3030
pub mod hot_patching {
31-
pub use crate::hot_patching::{call_hot, serve};
31+
pub use crate::hot_patching::{call_async, call_hot, serve};
3232
}

0 commit comments

Comments
 (0)