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}