tc_state/object/public/
instance.rs

1use std::fmt;
2
3use futures::future;
4use log::{debug, info};
5
6use tc_error::*;
7use tc_transact::public::generic::COPY;
8use tc_transact::public::{GetHandler, Handler, Route, ToState};
9use tc_transact::{Gateway, Transaction};
10use tcgeneric::{Instance, PathSegment, TCPath};
11
12use crate::object::InstanceExt;
13use crate::{CacheBlock, State};
14
15use super::method::route_attr;
16
17struct CopyHandler<'a, T> {
18    instance: &'a T,
19}
20
21impl<'a, Txn, T> Handler<'a, State<Txn>> for CopyHandler<'a, T>
22where
23    Txn: Transaction<CacheBlock> + Gateway<State<Txn>>,
24    T: Instance + fmt::Debug + 'a,
25{
26    fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, Txn, State<Txn>>>
27    where
28        'b: 'a,
29    {
30        Some(Box::new(move |_txn, _key| {
31            Box::pin(future::ready(Err(not_implemented!(
32                "{:?} has no /copy method",
33                self.instance
34            ))))
35        }))
36    }
37}
38
39impl<'a, T> From<&'a T> for CopyHandler<'a, T> {
40    fn from(instance: &'a T) -> Self {
41        Self { instance }
42    }
43}
44
45impl<Txn, T> Route<State<Txn>> for InstanceExt<Txn, T>
46where
47    Txn: Transaction<CacheBlock> + Gateway<State<Txn>>,
48    T: ToState<State<Txn>> + Instance + Route<State<Txn>> + fmt::Debug,
49    Self: ToState<State<Txn>>,
50{
51    fn route<'a>(
52        &'a self,
53        path: &'a [PathSegment],
54    ) -> Option<Box<dyn Handler<'a, State<Txn>> + 'a>> {
55        debug!(
56            "{:?} with members {:?} route {} (parent is {} {:?})",
57            self,
58            self.members(),
59            TCPath::from(path),
60            std::any::type_name::<T>(),
61            self.parent()
62        );
63
64        if path.is_empty() {
65            debug!("routing to parent: {:?}", self.parent());
66
67            if let Some(handler) = self.parent().route(path) {
68                Some(handler)
69            } else if path == &COPY[..] {
70                info!("tried to copy an public with no /copy method implemented");
71                Some(Box::new(CopyHandler::from(self)))
72            } else {
73                debug!("{:?} has no handler for {}", self, TCPath::from(path));
74                None
75            }
76        } else if let Some(attr) = self.members().get(&path[0]) {
77            debug!("{} found in {:?} members: {:?}", &path[0], self, attr);
78
79            if let State::Scalar(attr) = attr {
80                route_attr(self, &path[0], attr, &path[1..])
81            } else {
82                attr.route(&path[1..])
83            }
84        } else if let Some(attr) = self.proto().get(&path[0]) {
85            debug!("{} found in instance proto", &path[0]);
86            route_attr(self, &path[0], attr, &path[1..])
87        } else if let Some(handler) = self.parent().route(path) {
88            debug!("{} found in parent", TCPath::from(path));
89            Some(handler)
90        } else if let Some(attr) = self.proto().get(&path[0]) {
91            debug!("{} found in class proto", path[0]);
92            attr.route(&path[1..])
93        } else {
94            debug!(
95                "not found in {:?}: {} (while resolving {})",
96                self,
97                &path[0],
98                TCPath::from(path)
99            );
100
101            None
102        }
103    }
104}