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>),
}