abergmeier
abergmeier

Reputation: 14071

How to solve lifetime inside for_each

I try to get the following code to compile. Due to the buffer it wanted more explicit lifetimes inserted. So I tried that but still cannot figure out yet how to make it also work in for_each.

use std::{sync::mpsc::Sender, ffi::OsStr};

use inotify::{Event, EventMask, Inotify, WatchMask};

pub struct Watcher<'a> {
    buffer: [u8; 1024],
    sender: Sender<Event<&'a OsStr>>,
}

impl <'a> Watcher<'a> {
    pub fn new(sender: Sender<Event<&OsStr>>) -> Watcher{
        Watcher{
            buffer: [0; 1024],
            sender: sender,
        }
    }
    pub fn watch_for_led_directories(&mut self, dir: String) {
        let sender = self.sender.clone();
        let mut inotify = Inotify::init().expect("Error while initializing inotify instance");

        // Watch for modify and close events.
        inotify
            .add_watch(dir, WatchMask::CREATE | WatchMask::DELETE)
            .expect("Failed to add file watch");

        // Read events that were added with `add_watch` above.
        
        let events = inotify
            .read_events_blocking(&mut self.buffer)
            .expect("Error while reading events");

        events.filter(|e| -> bool { !e.mask.intersects(EventMask::ISDIR) }).for_each(|e| sender.send(e).unwrap());
    }
}

EDIT:

I ended up giving up on no-copy of strings:

use std::{ffi::OsStr, sync::mpsc::Sender};

use inotify::{Event, EventMask, Inotify, WatchMask};

pub struct Watcher {
    buffer: [u8; 1024],
    sender: Sender<Event<String>>,
}

impl Watcher {
    pub fn new(sender: Sender<Event<String>>) -> Watcher {
        Watcher {
            buffer: [0; 1024],
            sender: sender,
        }
    }
    pub fn watch_for_led_directories(&mut self, dir: String) {
        let sender = self.sender.clone();
        let mut inotify = Inotify::init().expect("Error while initializing inotify instance");

        // Watch for modify and close events.
        inotify
            .add_watch(dir, WatchMask::CREATE | WatchMask::DELETE)
            .expect("Failed to add file watch");

        // Read events that were added with `add_watch` above.

        let events = inotify
            .read_events_blocking(&mut self.buffer)
            .expect("Error while reading events");

        let filter = |e: &Event<&OsStr>| -> bool {
            !e.mask.intersects(EventMask::ISDIR) || e.name.is_none()
        };
        events.filter(filter).for_each(|e| {
            sender
                .send(Event {
                    cookie: e.cookie,
                    mask: e.mask,
                    name: Some(e.name.unwrap().to_str().expect("Expected valid unicode string").into()),
                    wd: e.wd,
                })
                .unwrap()
        });
    }
}

Upvotes: 0

Views: 107

Answers (1)

fred xia
fred xia

Reputation: 149

The issue is that while self has the lifetime of 'a, &mut self in watch_for_led_directories() has a different lifetime.

inotify.read_events_blocking() returns events that has the same lifetime as &mut self.buffer, which, as a mutable borrow, has the lifetime of &mut self. But sender is bound to life time 'a. Therefore compiler cannot reconcile these two lifetimes.

One way to solve it is to provide an external buffer, instead of having it owned by Watcher, e.g.:

pub fn watch_for_led_directories(&self, buffer: &'a mut [u8], dir: String) {
...
        let events: Events = inotify
            .read_events_blocking(buffer)
            .expect("Error while reading events");
...

Compiler derives the lifetime of events from buffer and therefore it will be 'a.

To use this method the externally allocated buffer must live at least as long as the Watcher object, which should not be too difficult to arrange.

Upvotes: 1

Related Questions