#pragma once #include #include "transfer.hpp" namespace saw { namespace rmt { struct Loopback {}; } template<> class remote; template class data_server, Encoding, rmt::Loopback> final : public i_data_server { private: typename impl::data_server_redux>::type>::type values_; ptr> remote_; public: data_server(remote_address& addr){ remote_().register_server(addr); } ~data_server(){ remote_().deregister_server(addr); } SAW_FORBID_COPY(data_server); SAW_FORBID_MOVE(data_server); /** * Return the schema id */ std::pair get_class_id() const override { uint32_t schema_hash = schema_hash>::apply(); uint32_t encode_hash = schema_hash::apply(); return std::make_pair(schema_hash, encode_hash); } /** * Get data from client */ template error_or send(const data& dat, id store_id){ auto& vals = std::get>>(values_); try { auto insert_res = vals.emplace(std::make_pair(store_id.get_value(), std::move(dat))); if(!insert_res.second){ return make_error(); } }catch(std::exception& ){ return make_error(); } return void_t{}; } /** * */ template error_or allocate(data::MetaSchema, Encoding> meta, id store_id){ auto& vals = std::get>>(values_); try { auto insert_res = vals.emplace(std::make_pair(store_id.get_value(), data::MetaSchema, Encoding>{std::move(meta)})); if(!insert_res.second){ return make_error(); } }catch(std::exception& ){ return make_error(); } return make_void(); } template error_or> receive(id store_id){ auto& vals = std::get>>(values_); auto find_res = vals.find(store_id.get_value()); if(find_res == vals.end()){ return make_error(); } auto& dat = find_res->second; return dat; } template error_or erase(id store_id){ auto& vals = std::get>>(values_); auto erase_op = vals.erase(store_id.get_value()); if(erase_op == 0u){ return make_error(); } return void_t{}; } template error_or*> find(id store_id){ auto& vals = std::get>>(values_); auto find_res = vals.find(store_id.get_value()); if(find_res == vals.end()){ return make_error(); } auto& dat = find_res->second; return &dat; } }; /** * Client for transporting data to remote and receiving data back */ template class data_client, Encoding, rmt::Loopback> { private: /** * Corresponding server for this client */ data_server, Encoding, rmt::Loopback>* srv_; /** * The next id for identifying issues on the remote side. */ uint64_t next_id_; public: /** * Main constructor */ data_client(data_server, Encoding, rmt::Loopback>& srv__): srv_{&srv__}, next_id_{0u} {} /** * Send data to the remote. */ template error_or> send(const data& dat){ id dat_id{next_id_}; auto eov = srv_->send(dat, dat_id); if(eov.is_error()){ auto& err = eov.get_error(); return std::move(err); } ++next_id_; return dat_id; } /** * Preallocate data */ template error_or> allocate(const data::MetaSchema, Encoding>& meta){ id dat_id{next_id_}; auto eov = srv_->allocate(meta, dat_id); if(eov.is_error()){ auto& err = eov.get_error(); return std::move(err); } ++next_id_; return dat_id; } /** * Receive data */ template conveyor> receive(id dat_id){ auto eov = srv_->receive(dat_id); if(eov.is_error()){ auto& err = eov.get_error(); return std::move(err); } auto& val = eov.get_value(); return std::move(val); } /** * Erase data */ template error_or erase(id dat_id){ return srv_->erase(dat_id); } /** * An exception for the Loopback backend. Here we can safely use find from * the client side. */ template error_or*> find(id dat_id){ auto eov = srv_->find(dat_id); if(eov.is_error()){ auto& err = eov.get_error(); return std::move(err); } auto val = eov.get_value(); return val; } }; }