vfs/directory/
dirents_sink.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//! Types that help describe `get_entry_names` callback for the lazy directories.
6
7use crate::directory::entry::EntryInfo;
8
9use std::any::Any;
10
11/// Every sink that can consume directory entry information implements this trait.
12pub trait Sink: Send {
13    /// Try to append an entry with the specified entry name and attributes into this sink.
14    /// If the entry was successfully added the result is [`AppendResult::Ok`].  If the sink could
15    /// could not consume this entry an [`AppendResult::Sealed`] value is returned.
16    ///
17    /// `entry` is the [`EntryInfo`] attributes of the next entry.  `name` is the name of the next
18    /// entry.
19    fn append(self: Box<Self>, entry: &EntryInfo, name: &str) -> AppendResult;
20
21    /// If the producer has reached the end of the list of entries, it should call this method to
22    /// produce a "sealed" sink.
23    fn seal(self: Box<Self>) -> Box<dyn Sealed>;
24}
25
26/// When a sink has reached it's full capacity or when the producer has exhausted all the values it
27/// had, sink is transformed into a value that implements this trait.  It helps to reduce the
28/// number of possible states the sink has.  Once "sealed" it can not be converted back into a
29/// [`Sink`] instance.  And the only way forward is to call the [`Self::open()`] method to downcast
30/// sink into the underlying type that gives access to the data that the sink have stored.
31pub trait Sealed: Send {
32    /// Converts a "sealed" sink into [`Any`] that can be later cast into a specific type that the
33    /// consumer of the full sink can use to extract contained data.
34    ///
35    /// TODO It would be awesome to have a method that converts `Sealed` into a specific underlying
36    /// type directly.  With the underlying type somehow only known by the code that constructed
37    /// the `Sink` in the first place.  And not to the code that is operating on the
38    /// `Sink`/`Sealed` values via the trait.  But I could not find a way to express that.
39    ///
40    /// Seems like an associated type would express that, but if I add an associated type to both
41    /// `Sink` and `Sealed`, I need any method that consumes the sink to be generic over this type.
42    /// And that means that sink consumers are not object safe :(  I think generic methods might be
43    /// object safe, as long as they do not use their type arguments, which seems pointless, but
44    /// here would be used to make sure that the type of the returned object is preserved.  Maybe
45    /// `?Sized` would be a good boundary for generic methods allowed in traits?
46    fn open(self: Box<Self>) -> Box<dyn Any>;
47}
48
49/// Result of the [`Sink::append`] method. See there for details.
50pub enum AppendResult {
51    /// Sink have consumed the value and may consume more.
52    Ok(Box<dyn Sink>),
53    /// Sink could not consume the last value provided.
54    Sealed(Box<dyn Sealed>),
55}