vfs/directory/watchers/
event_producers.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! When generating a watcher event, one needs "a list of names" that are then converted into
6//! buffers sent to the watchers.  In a sense, an iterator over a list of strings would work, but
7//! in order to avoid copying the data around, this namespace provides a more specialized version
8//! of this abstraction.
9
10use fidl_fuchsia_io as fio;
11use static_assertions::const_assert;
12
13/// Watcher event producer, that generates buffers filled with watcher events.  Watchers use this
14/// API to obtain buffers that are then sent to the actual watchers.  Every producer may generate
15/// multiple events, but they all need to be of the same type, as returned by [`Self::event()`] and
16/// [`Self::mask()`] methods.
17pub trait EventProducer {
18    /// Returns a mask that represents the type of events this producer can generate, as one of the
19    /// `fidl_fuchsia_io::WatchMask::*` constants.  There might be only one bit set and it should
20    /// correspond to the event returned by the [`Self::event()`] method.  It is a duplication, but it
21    /// helps the callers that need both masks and event IDs.
22    fn mask(&self) -> fio::WatchMask;
23
24    /// Returns an event ID this event producer will use to populate the buffers, as one of the
25    /// `fidl_fuchsia_io::WatchEvent::*` constants.  Must match what [`Self::mask()`], returns, see
26    /// there for details.
27    fn event(&self) -> fio::WatchEvent;
28
29    /// Checks if this producer can create another buffer, returning `true` if it can.  This method
30    /// does not actually need to construct the buffer just yet, as an optimization if it will not
31    /// be needed.
32    fn prepare_for_next_buffer(&mut self) -> bool;
33
34    /// Returns a copy of the current buffer prepared by this producer.  This method will be the
35    /// one constructing a buffer, if necessary, after a preceding call to
36    /// [`Self::prepare_for_next_buffer()`].
37    ///
38    /// Note that this method will keep returning copies of the same buffer, until
39    /// [`Self::prepare_for_next_buffer()`] is not called explicitly.
40    fn buffer(&mut self) -> Vec<u8>;
41}
42
43/// An [`EventProducer`] that uses a `Vec<String>` with names of the entires to be put into the
44/// watcher event.
45pub struct StaticVecEventProducer {
46    names: Vec<String>,
47    next: usize,
48    mask: fio::WatchMask,
49    event: fio::WatchEvent,
50    buffer: Vec<u8>,
51}
52
53impl StaticVecEventProducer {
54    /// Constructs a new [`EventProducer`] that is producing names form the specified list,
55    /// building events of type `WatchEvent::Added`.  `names` is not allowed to be empty.
56    pub fn added(names: Vec<String>) -> Self {
57        Self::new(fio::WatchMask::ADDED, fio::WatchEvent::Added, names)
58    }
59
60    /// Constructs a new [`EventProducer`] that is producing names form the specified list,
61    /// building events of type `WatchEvent::Removed`.  `names` is not allowed to be empty.
62    pub fn removed(names: Vec<String>) -> Self {
63        Self::new(fio::WatchMask::REMOVED, fio::WatchEvent::Removed, names)
64    }
65
66    /// Constructs a new [`EventProducer`] that is producing names form the specified list,
67    /// building events of type `WatchEvent::Existing`.  `names` is not allowed to be empty.
68    pub fn existing(names: Vec<String>) -> Self {
69        Self::new(fio::WatchMask::EXISTING, fio::WatchEvent::Existing, names)
70    }
71
72    fn new(mask: fio::WatchMask, event: fio::WatchEvent, names: Vec<String>) -> Self {
73        debug_assert!(!names.is_empty());
74        Self { names, next: 0, mask, event, buffer: Vec::new() }
75    }
76}
77
78impl EventProducer for StaticVecEventProducer {
79    fn mask(&self) -> fio::WatchMask {
80        self.mask
81    }
82
83    fn event(&self) -> fio::WatchEvent {
84        self.event
85    }
86
87    fn prepare_for_next_buffer(&mut self) -> bool {
88        self.buffer.clear();
89        self.next < self.names.len()
90    }
91
92    fn buffer(&mut self) -> Vec<u8> {
93        if self.buffer.is_empty() {
94            while self.next < self.names.len() {
95                if !encode_name(&mut self.buffer, self.event, &self.names[self.next]) {
96                    break;
97                }
98                self.next += 1;
99            }
100        }
101        self.buffer.clone()
102    }
103}
104
105/// An event producer for an event containing only one name.
106pub struct SingleNameEventProducer<'a> {
107    name: &'a str,
108    buffer: Vec<u8>,
109    mask: fio::WatchMask,
110    event: fio::WatchEvent,
111}
112
113impl<'a> SingleNameEventProducer<'a> {
114    /// Constructs a new [`SingleNameEventProducer`] that will produce an event for one name of
115    /// type `WatchEvent::Deleted`. Deleted refers to the directory the watcher itself is on, and
116    /// therefore statically refers to itself as ".".
117    pub fn deleted() -> Self {
118        Self::new(fio::WatchMask::DELETED, fio::WatchEvent::Deleted, ".")
119    }
120
121    /// Constructs a new [`SingleNameEventProducer`] that will produce an event for one name of
122    /// type `WatchEvent::Added`.
123    pub fn added(name: &'a str) -> Self {
124        Self::new(fio::WatchMask::ADDED, fio::WatchEvent::Added, name)
125    }
126
127    /// Constructs a new [`SingleNameEventProducer`] that will produce an event for one name of
128    /// type `WatchEvent::Removed`.
129    pub fn removed(name: &'a str) -> Self {
130        Self::new(fio::WatchMask::REMOVED, fio::WatchEvent::Removed, name)
131    }
132
133    /// Constructs a new [`SingleNameEventProducer`] that will produce an event for one name of
134    /// type `WatchEvent::Existing`.
135    pub fn existing(name: &'a str) -> Self {
136        Self::new(fio::WatchMask::EXISTING, fio::WatchEvent::Existing, name)
137    }
138
139    /// Constructs a new [`SingleNameEventProducer`] that will produce an `WatchEvent::Idle` event.
140    pub fn idle() -> Self {
141        Self::new(fio::WatchMask::IDLE, fio::WatchEvent::Idle, "")
142    }
143
144    fn new(mask: fio::WatchMask, event: fio::WatchEvent, name: &'a str) -> Self {
145        Self { name, buffer: Vec::new(), mask, event }
146    }
147}
148
149impl EventProducer for SingleNameEventProducer<'_> {
150    fn mask(&self) -> fio::WatchMask {
151        self.mask
152    }
153
154    fn event(&self) -> fio::WatchEvent {
155        self.event
156    }
157
158    fn prepare_for_next_buffer(&mut self) -> bool {
159        // The buffer is populated the first time `EventProducer::buffer` is called. If the buffer
160        // is empty then we are able to produce another buffer. If the buffer is already populated
161        // then this event has already been sent.
162        self.buffer.is_empty()
163    }
164
165    fn buffer(&mut self) -> Vec<u8> {
166        if self.buffer.is_empty() {
167            encode_name(&mut self.buffer, self.event, self.name);
168        }
169        self.buffer.clone()
170    }
171}
172
173fn encode_name(buffer: &mut Vec<u8>, event: fio::WatchEvent, name: &str) -> bool {
174    let event_size = 2 + name.len();
175    if buffer.len() + event_size > fio::MAX_BUF as usize {
176        return false;
177    }
178
179    // We are going to encode the file name length as u8.
180    const_assert!(u8::max_value() as u64 >= fio::MAX_NAME_LENGTH);
181
182    buffer.reserve(event_size);
183    buffer.push(event.into_primitive());
184    buffer.push(name.len() as u8);
185    buffer.extend_from_slice(name.as_bytes());
186    true
187}