Smithay / calloop

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

Advice on Metadata in EventSource of Timer #105

Closed Christina2333 closed 2 years ago

Christina2333 commented 2 years ago

impl EventSource for Timer { type Event = Instant; type Metadata = (); type Ret = TimeoutAction; type Error = std::io::Error;

... ... }

Because Metadata of Timer is (), specific data cannot be passed in the callback function of Timer. Why not add a generic to Timer to support specific Metadata? Thanks.

elinorbgr commented 2 years ago

So you want some Timer-specific data, rather than using the global dispatching data mechanism of calloop?

Christina2333 commented 2 years ago

Thanks for your reply. I'm not sure if I'm using calloop in a wrong way. I'll show how I want to use it.

pub struct Aa {
      // something
}
pub fn foo(tmp: Aa) {
     // do something
}
fn main() {
    let mut event_loop: EventLoop<LoopSignal> = EventLoop::try_new()
        .expect("Failed to initialize the event loop");
    let handle = event_loop.handle();
    // pass a generic?maybe actualy a `PhantomData` type?
    let timer = Timer<Aa>::from_duration(std::time::Duration::from_secs(10));
    let res = handle
        .insert_source(
            timer,
            |event, _metadata, shared_data| {
                // pass _metadata to a function
                foo(_metadata);
                shared_data.stop();
                TimeoutAction::Drop
            },
        )
        .expect("Failed to insert event source!");
}

So you want some Timer-specific data, rather than using the global dispatching data mechanism of calloop?

elinorbgr commented 2 years ago

I'm starting to suspect we have a confusing example. 🤔

The LoopSignal type parameter of the event loop can be any type you want, and the &mut T you pass as argument to dispatch() is forwarded to all callbacks as the shared_data argument to the closure.

Using your Aa struct as the shared data does not fit your need?

Christina2333 commented 2 years ago

I'm starting to suspect we have a confusing example. 🤔

The LoopSignal type parameter of the event loop can be any type you want, and the &mut T you pass as argument to dispatch() is forwarded to all callbacks as the shared_data argument to the closure.

Using your Aa struct as the shared data does not fit your need?

How can I stop the event loop if the shared_data is not type of LoopSignal? LoopSignal cannot be a field of Aa as it has no constructor

elinorbgr commented 2 years ago

What do you mean it has no constructor?

The way calloop is designed is that you're supposed to construct youself an instance of the shared data type you pass to the event loop when invoking dispatch() or run(), so the classic structure of a calloop-based app would be something like this:

  1. Create the EventLoop and get the LoopHandle and LoopSignal from it if you need them
  2. Create and instance of your shared data as a struct that may contain a LoopHandle / LoopSignal as fields if you need
  3. Setup your initial event sources as you need them
  4. invoke EventLoop::run(), passing it a &mut reference to the shared data struct you created earlier

This way, all the state you've put in the shared data struct (including any LoopHandle / LoopSignal) can be accessed from all you callbacks.

Christina2333 commented 2 years ago

My following question is how to assign value to LoopSignal in Aa. I probably know it now.

pub struct Aa {
    fd: i32,
    tmp: String,
    signal: LoopSignal
}

impl Aa {
    pub fn new(fd: i32, tmp: String, event: &EventLoop<Aa>) -> Aa {
        Aa {
            fd,
            tmp,
            // pass EventLoop to get the LoopSignal
            signal: event.get_signal()
        }
    }
}

pub fn foo(tmp: &mut Aa) {
}

fn main() {
    let mut event_loop: EventLoop<Aa> = EventLoop::try_new()
        .expect("Failed to initialize the event loop");

    let mut aa = Aa::new(6, String::from("test"), &event_loop);

    let handle = event_loop.handle();

    let timer = Timer::from_duration(std::time::Duration::from_secs(2));
    let res = handle
        .insert_source(
            timer,
            |event, _metadata, shared_data| {
                println!("Timeout for {:?} expired", event);
                foo(shared_data);
                // stop the event loop
                shared_data.signal.stop();
                TimeoutAction::Drop
            },
        )
        .expect("Failed to insert event source!");
}

Thanks!