meshed/
extract.rs

1/*
2 * Copyright [2022] [Kevin Velasco]
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use crate::identify::{Identifiable, Identity};
18
19use std::collections::HashMap;
20use std::fmt::Display;
21use std::marker::PhantomData;
22use std::rc::Rc;
23
24/// Be able to query some type given an identifier. It must return a type that
25/// can be queried for more values like itself.
26///
27/// Query a datastore for a type that can be used to find more like it
28pub trait Query<I, V>
29where
30    I: Identity,
31    V: Identifiable<I>,
32{
33    fn query(&self, identifier: &I) -> Option<&V>;
34
35    fn all(&self) -> Vec<&V>;
36
37    fn create_index(&self) -> HashMap<I, Link<I, V>> {
38        let mut map: HashMap<_, _> = Default::default();
39        let values = self.all();
40        for value in values {
41            map.insert(value.get_id(), Link::Value(value));
42        }
43        map
44    }
45}
46
47impl<'a, I, V, T> Query<I, V> for &'a T
48where
49    T: Query<I, V>,
50    I: Identity,
51    V: Identifiable<I>,
52{
53    fn query(&self, identifier: &I) -> Option<&V> {
54        T::query(self, identifier)
55    }
56    fn all(&self) -> Vec<&V> {
57        T::all(self)
58    }
59}
60
61pub struct Edge<I: Identity, Meta> {
62    pub source: I,
63    pub sink: I,
64    pub order: usize,
65    pub meta: Rc<Meta>,
66}
67
68impl<I: Identity, M> Clone for Edge<I, M> {
69    fn clone(&self) -> Self {
70        Self {
71            source: self.source.clone(),
72            sink: self.sink.clone(),
73            order: self.order,
74            meta: Rc::clone(&self.meta),
75        }
76    }
77}
78
79impl<I, M> Edge<I, M>
80where
81    I: Identity,
82{
83    pub fn new(source: I, sink: I, order: usize, meta: M) -> Self {
84        Self {
85            source,
86            sink,
87            order,
88            meta: Rc::new(meta),
89        }
90    }
91}
92
93/// Be able to derive a set of identifiers from a given item. Semantically this is
94/// Get "children" but not all graph operations are parent-child.
95///
96/// Given a type, find the next set of identities I that I need to traverse
97/// Metadata may also be optionally returned via the E value
98pub trait Edges<I, D>
99where
100    I: Identity,
101{
102    fn next_edge(&self, previous_edge_index: Option<usize>) -> Option<Edge<I, D>>;
103    fn edges(&self) -> EdgeIterator<'_, I, D, Self>
104    where
105        Self: Sized,
106    {
107        EdgeIterator {
108            last_edge_index: None,
109            node_meta: Default::default(),
110            edges: &self,
111        }
112    }
113}
114
115pub trait ExtractData<D: 'static> {
116    fn extract_data(&self) -> D;
117}
118
119impl<T> ExtractData<()> for T {
120    fn extract_data(&self) {}
121}
122
123macro_rules! extract_data_impl {
124    ($(($($tup:tt), +)) +) => {
125        $(
126            impl <T, $($tup),+> ExtractData<($($tup),+)> for T
127            where
128                $(T: ExtractData<$tup>), *,
129                $($tup: 'static), *
130
131            {
132                fn extract_data(&self) -> ($($tup),+) {
133                    ( $(<Self as ExtractData<$tup>>::extract_data(&self)), *  )
134                }
135            }
136        )+
137    }
138}
139
140extract_data_impl! {
141    (D1, D2)
142    (D1, D2, D3)
143    (D1, D2, D3, D4)
144    (D1, D2, D3, D4, D5)
145    (D1, D2, D3, D4, D5, D6)
146    (D1, D2, D3, D4, D5, D6, D7)
147    (D1, D2, D3, D4, D5, D6, D7, D8)
148    (D1, D2, D3, D4, D5, D6, D7, D8, D9)
149    (D1, D2, D3, D4, D5, D6, D7, D8, D9, D10)
150}
151
152/// Label for a node. The label type must be very cheap to clone and move around.
153/// for strings, Arc<str> or Rc<str> is preferred when implementing this type.
154///
155/// ```rust
156///# use std::fmt::Formatter;
157/// use meshed::prelude::*;
158/// use std::rc::Rc;
159///
160/// #[derive(Clone)]
161/// struct Identifier(Rc<str>);
162///
163/// impl std::fmt::Display for Identifier {
164///   fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
165///         todo!()
166///   }
167/// }
168///
169/// struct Data {
170///     id: Identifier
171/// }
172///
173/// impl Label for Data {
174///     type Label = Identifier;
175///     fn label(&self) -> Self::Label {
176///        self.id.clone()
177///     }
178/// }
179///
180/// ```
181pub trait Label {
182    type Label: Display + Clone;
183    fn label(&self) -> Self::Label;
184}
185
186pub struct EdgeIterator<'a, I: Identity, E, ED>
187where
188    ED: Edges<I, E>,
189{
190    last_edge_index: Option<usize>,
191    node_meta: PhantomData<(I, E)>,
192    edges: &'a ED,
193}
194
195impl<'a, I, E, Ed> Iterator for EdgeIterator<'a, I, E, Ed>
196where
197    I: Identity,
198    Ed: Edges<I, E>,
199{
200    type Item = Edge<I, E>;
201    fn next(&mut self) -> Option<Self::Item> {
202        let next = self.edges.next_edge(self.last_edge_index.take())?;
203        self.last_edge_index = Some(next.order);
204        Some(next)
205    }
206}
207
208pub enum Link<'a, I, V> {
209    Link(I),
210    Value(&'a V),
211}
212
213impl<'a, I, V> Query<I, V> for HashMap<I, Link<'a, I, V>>
214where
215    I: Identity,
216    V: Identifiable<I>,
217{
218    fn query(&self, identifier: &I) -> Option<&V> {
219        let mut current = self.get(identifier)?;
220
221        loop {
222            match current {
223                Link::Link(follow) => {
224                    current = self.get(follow).expect("Unable to follow link in index");
225                }
226                Link::Value(output) => return Some(output),
227            }
228        }
229    }
230
231    fn all(&self) -> Vec<&V> {
232        self.values()
233            .filter_map(|value| match value {
234                Link::Link(_) => None,
235                Link::Value(v) => Some(*v),
236            })
237            .collect()
238    }
239}