Skip to main content

harmos_domain/
catalog.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12/* === Re-Exports === */
13
14pub use crate::inventory::observers::Entry as ObserverEntry;
15pub use crate::inventory::publications::Entry as PublicationEntry;
16pub use crate::listeners::Entry as ListenerEntry;
17pub use crate::operations::{Entry as OperationEntry, WireDeclaration as WireEntry};
18pub use crate::plugin::Requirement as RequirementEntry;
19
20/* === Imports === */
21
22// Standard Library Imports
23
24// Third Party Imports
25
26// Local Imports
27
28/* === Constants === */
29
30/* === Macros === */
31
32/* === Type Aliases === */
33
34/* === Structs === */
35
36/* === Enums === */
37
38pub enum Node<E: 'static> {
39    Leaf(E),
40    Nested(&'static [Node<E>]),
41}
42
43/* === Traits === */
44
45pub trait Visitor {
46    type Entry: 'static;
47}
48
49pub trait Member<T>: Visitor {
50    const ENTRY: Self::Entry;
51}
52
53pub trait Projection<E> {
54    const LEN: usize;
55
56    fn try_for_each<F>(&self, visit: impl FnMut(&E) -> Result<(), F>) -> Result<(), F>;
57}
58
59pub trait InertCatalog<V: Visitor<Entry = E>, E: 'static> {
60    const ENTRIES: &'static [Node<E>];
61    const LEN: usize = count(Self::ENTRIES);
62}
63
64pub trait Catalog<V: Visitor> {
65    type Entries: Projection<V::Entry>;
66    const ENTRIES: Self::Entries;
67}
68
69pub trait Contains<T> {}
70
71/* === Implementations === */
72
73impl<E, const N: usize> Projection<E> for [E; N] {
74    const LEN: usize = N;
75
76    fn try_for_each<F>(&self, mut visit: impl FnMut(&E) -> Result<(), F>) -> Result<(), F> {
77        for entry in self {
78            visit(entry)?;
79        }
80        Ok(())
81    }
82}
83
84impl<E> Projection<E> for () {
85    const LEN: usize = 0;
86
87    fn try_for_each<F>(&self, _: impl FnMut(&E) -> Result<(), F>) -> Result<(), F> {
88        Ok(())
89    }
90}
91
92impl<E, L: Projection<E>, R: Projection<E>> Projection<E> for (L, R) {
93    const LEN: usize = match L::LEN.checked_add(R::LEN) {
94        Some(len) => len,
95        None => panic!("catalog leaf count overflows usize"),
96    };
97
98    fn try_for_each<F>(&self, mut visit: impl FnMut(&E) -> Result<(), F>) -> Result<(), F> {
99        self.0.try_for_each(&mut visit)?;
100        self.1.try_for_each(visit)
101    }
102}
103
104impl<V: Visitor> Catalog<V> for () {
105    type Entries = [V::Entry; 0];
106    const ENTRIES: Self::Entries = [];
107}
108
109impl<V: Visitor<Entry = E>, E: 'static> InertCatalog<V, E> for () {
110    const ENTRIES: &'static [Node<E>] = &[];
111}
112
113/* === Public Functions === */
114
115pub const fn count<E>(nodes: &[Node<E>]) -> usize {
116    let mut len: usize = 0;
117    let mut index = 0;
118    while index < nodes.len() {
119        let added = match &nodes[index] {
120            Node::Leaf(_) => 1,
121            Node::Nested(nested) => count(nested),
122        };
123        len = match len.checked_add(added) {
124            Some(len) => len,
125            None => panic!("catalog leaf count overflows usize"),
126        };
127        index += 1;
128    }
129    len
130}
131
132pub fn try_for_each<E, F>(nodes: &[Node<E>], mut visit: impl FnMut(&E) -> Result<(), F>) -> Result<(), F> {
133    visit_nodes(nodes, &mut visit)
134}
135
136/* === Private Functions === */
137
138fn visit_nodes<E, F>(nodes: &[Node<E>], visit: &mut impl FnMut(&E) -> Result<(), F>) -> Result<(), F> {
139    for node in nodes {
140        match node {
141            Node::Leaf(entry) => visit(entry)?,
142            Node::Nested(nested) => visit_nodes(nested, visit)?,
143        }
144    }
145    Ok(())
146}
147
148/* === Tests === */