Search code examples
network-programmingrustproxyreference

expected `&Arc<ProxyPool>`, found `&ProxyPool`


I try to clone a reference from &ProxyPool to &Arc<ProxyPool> but im still getting an error, the type of the reference is still &ProxyPool.

pub struct ProxyPool {
    connections: Mutex<Vec<TcpStream>>,
    proxy_addresses: Arc<Vec<SocketAddr>>,
}
pub struct PooledConnection {
    stream: TcpStream,
    pool: Arc<ProxyPool>,
}

impl ProxyPool {
    async fn get_connection(&self) -> Result<PooledConnection> {
        loop {
            if let Some(conn) = {
                let mut connections = self.connections.lock().unwrap();
                connections.pop()
            } {
                return Ok(PooledConnection {
                    stream: conn,
                    pool: Arc::clone(self), // converting &ProxyPool to Arc<ProxyPool>
                });
            }
            // If no connection is available, wait a bit and try again.
            tokio::time::sleep(Duration::from_millis(100)).await;
        }
    }

    fn return_connection(&self, conn: TcpStream) {
        let mut connections = self.connections.lock().unwrap();
        connections.push(conn);
    }

    fn get_random_proxy_address(&self) -> SocketAddr {
        let idx = rand::random::<usize>() % self.proxy_addresses.len();
        self.proxy_addresses[idx]
    }
}

any ideas why this is happen?

204 |                     pool: Arc::clone(self), // Convert &ProxyPool to Arc<ProxyPool>
    |                           ---------- ^^^^ expected `&Arc<ProxyPool>`, found `&ProxyPool`

I have already tried to create a new Arc and clone of self reference


Solution

  • Turning arbitrary references into an Arc is not possible, after all the owner might not be an Arc to begin with. You can fix that problem in your case by just changing the receiver to be an Arc<Self>:

        async fn get_connection(self: Arc<Self>) -> Result<PooledConnection, ()> {
            loop {
                if let Some(conn) = {
                    let mut connections = self.connections.lock().unwrap();
                    connections.pop()
                } {
                    return Ok(PooledConnection {
                        stream: conn,
                        pool: self,
                    });
                }
                // If no connection is available, wait a bit and try again.
                tokio::time::sleep(Duration::from_millis(100)).await;
            }
        }
    

    And adjusting the callsites.

    I'd prefer taking a Arc<Self> over &Arc<Self> here since you know you need an owned Arc and this way the caller can decide to pass you one they already have or Arc::clone it themselves if they want to keep it or only have a reference.