Trying to get a better grasp of traits and generics, so building a simple tcp server master-slave like library, currently I have this layout
pub struct MyStruct<Output, Stream, Store>
where
Output: StoreOutput,
Stream: AsyncStream,
Store: Storage<Output>,
{
node: Arc<RwLock<Node<Stream>>>,
store: Arc<RwLock<Store>>,
_marker: PhantomData<Output>,
}
impl<Output, Store> MyStruct<Output, TcpStream, Store>
where
Output: StoreOutput,
Store: Storage<Output>,
{
pub async fn run(&self) -> io::Result<()> {
if let NodeRole::Replica(master) = self.role().await {
let remote: Connection<TcpStream> = Connection::from_addr(master).await.unwrap();
let _ = sync(remote, self.node.clone(), self.store.clone()).await;
}
let listener = self.node.read().await.listen().await?;
loop {
if let Ok((conn, _addr)) = listener.accept().await {
self.handle(conn);
}
}
}
}
pub async fn sync<Output, Stream, Store>(
remote: Connection<Stream>,
node: SharedNode<Stream>,
store: SharedStore<Store>,
) where
Output: StoreOutput,
Stream: AsyncStream,
Store: Storage<Output>,
{
let (uuid, addr) = {
let lock = node.read().await;
(lock.uuid(), lock.addr())
};
let (conn, remote_store) = actions::get_subscription(uuid, addr, remote).await.unwrap();
let _ = store.write().await.initialize::<Store>(remote_store).unwrap();
let _ = sync_routine::<Output, Stream, Store>(conn, node, store);
}
I understand that calling MyStruct::run()
works because the impl uses Stream
as a concrete type TcpStream
.
So in another function, doing this fails:
async fn handle_cmd<'cmd, Output, Stream, Store>(
mut conn: net::Connection<Stream>,
cmd: Command<'cmd>,
node: SharedNode<Stream>,
store: SharedStore<Store>,
) -> Result<(), HandleError>
where
Output: StoreOutput,
Stream: AsyncStream,
Store: Storage<Output>,
{
match &cmd {
Command::Redirect(args) => {
let remote = Connection::from_addr(args[0].parse().unwrap()).await.unwrap();
let node: Arc<RwLock<Node<Stream>>> = Arc::clone(&node);
let _ = sync(remote, node, store).await; // FAILS with: mismatched types
// expected struct `Arc<tokio::sync::RwLock<Node<tokio::net::TcpStream>>>`
// found struct `Arc<tokio::sync::RwLock<Node<Stream>>>`
},
_ => {}
}
Ok(())
}
Since Connection::from_addr
returns a Connection<TcpStream>
instead of a generic one, and does not match with Node<Stream
which is generic, what is the best way to proceed here? should I duplicate the async fn handle_cmd<'cmd, Output, Stream, Store>
implementation, one for Stream, Stream
and one for TcpStream, TcpStream
?