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