use std::fmt;
use futures::future;
use log::{debug, info};
use tc_error::*;
use tc_transact::public::generic::COPY;
use tc_transact::public::{GetHandler, Handler, Route, ToState};
use tcgeneric::{Instance, PathSegment, TCPath};
use crate::object::InstanceExt;
use crate::{State, Txn};
use super::method::route_attr;
struct CopyHandler<'a, T> {
instance: &'a T,
}
impl<'a, T> Handler<'a, State> for CopyHandler<'a, T>
where
T: Instance + fmt::Debug + 'a,
{
fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, Txn, State>>
where
'b: 'a,
{
Some(Box::new(move |_txn, _key| {
Box::pin(future::ready(Err(not_implemented!(
"{:?} has no /copy method",
self.instance
))))
}))
}
}
impl<'a, T> From<&'a T> for CopyHandler<'a, T> {
fn from(instance: &'a T) -> Self {
Self { instance }
}
}
impl<T: ToState<State> + Instance + Route<State> + fmt::Debug> Route<State> for InstanceExt<T>
where
Self: ToState<State>,
{
fn route<'a>(&'a self, path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a, State> + 'a>> {
debug!(
"{:?} with members {:?} route {} (parent is {} {:?})",
self,
self.members(),
TCPath::from(path),
std::any::type_name::<T>(),
self.parent()
);
if path.is_empty() {
debug!("routing to parent: {:?}", self.parent());
if let Some(handler) = self.parent().route(path) {
Some(handler)
} else if path == ©[..] {
info!("tried to copy an public with no /copy method implemented");
Some(Box::new(CopyHandler::from(self)))
} else {
debug!("{:?} has no handler for {}", self, TCPath::from(path));
None
}
} else if let Some(attr) = self.members().get(&path[0]) {
debug!("{} found in {:?} members: {:?}", &path[0], self, attr);
if let State::Scalar(attr) = attr {
route_attr(self, &path[0], attr, &path[1..])
} else {
attr.route(&path[1..])
}
} else if let Some(attr) = self.proto().get(&path[0]) {
debug!("{} found in instance proto", &path[0]);
route_attr(self, &path[0], attr, &path[1..])
} else if let Some(handler) = self.parent().route(path) {
debug!("{} found in parent", TCPath::from(path));
Some(handler)
} else if let Some(attr) = self.proto().get(&path[0]) {
debug!("{} found in class proto", path[0]);
attr.route(&path[1..])
} else {
debug!(
"not found in {:?}: {} (while resolving {})",
self,
&path[0],
TCPath::from(path)
);
None
}
}
}