Smithay / calloop

A callback-based Event Loop
MIT License
176 stars 35 forks source link

Can callback functions be nested? #107

Closed Christina2333 closed 2 years ago

Christina2333 commented 2 years ago

I'm trying to write a server with calloop that handles read and write events. First, The event loop should listen to the server socket and wait for the client to connect. Second, If a client connects to this socket, the event loop will process read write events from the client.

1 fn main() {
2    let mut event_loop: EventLoop<i32> = EventLoop::try_new().expect("Failed to initialize the event loop");
3    // server socket
4    let socket = bind_ipc_socket("/xxx");
5    // wait for client to connect
6    event_loop.handle().insert_source(
7        Generic::new(socket, Interest::READ, Mode::Edge),
8        |event, metadata, shared_data| {
9            // accept the client
10            let rw_socket = accept_client(*metadata);
11            // wait for the message from the connected client
12            event_loop.handle().insert_source(
13               Generic::new(rw_socket, Interest::READ, Mode::Edge),
14                |event, metadata, shared_data| {
15                    // process read or write event from client
16                    process_message(*metadata);
17                    core::result::Result::Ok(PostAction::Continue)
18                }
19            );
20            core::result::Result::Ok(PostAction::Continue)
21        }
22    );
23 }
fn bind_ipc_socket(path: &str) -> i32 {}
fn accept_client(socket: i32) -> i32 {}
fn process_message(socket: i32) {}

I get the following error when running:

error[E0597]: `event_loop` does not live long enough
  --> src/main.rs:12:13
   |
8 |         |event, metadata, shared_data| {
   |         ------------------------------ value captured here
...
12 |             event_loop.handle().insert_source(
   |             ^^^^^^^^^^ borrowed value does not live long enough
...
23 | }
   | -
   | |
   | `event_loop` dropped here while still borrowed
   | borrow might be used here, when `event_loop` is dropped and runs the destructor for type `EventLoop<'_, i32>`

I'm confused about that. Can callback functions be nested? Or there is another way to deal with. Thanks a lot.

elinorbgr commented 2 years ago

Yes, the issue in your code is that the first closure attempts to borrow the event_loop from the main function.

You can avoid that by creating an explicit variable let handle = event_loop.handle() in your main function, and then using handle instead of event_loop.handle() in your callback. You'll also need to define the closure as capturing its environment by value, using the move keyword: move |event, metadata, shared_data| { ... }.

Christina2333 commented 2 years ago

Thanks!! It works.