如何将 JS Promise 翻译为 Rust

Sna*_*gon 4 rust rust-tokio

目前我正在编写一个纯 Rust MQTT5 库(我知道那里有现有的库,但我更想学习 Rust),我偶然发现了这个问题。

我正在使用最新的稳定版 rust 和 tokio 1.0.1。

当我通过线路发送数据包时,我经常期望服务器做出响应(下面的示例是 PingReq/PingAck、Ping/Pong)。

省略了很多有关超时和数据包冲突的逻辑,我用 JavaScript 编写了逻辑的简化版本(因为我对此非常了解)。

这种逻辑将如何转化为 Rust 及其未来?或者更清楚地说:我可以以某种方式重新创建awaitPackage + onIncomingPacket 的resolve() 回调函数行为吗?

class Client {
  awaitedPacketTypes = {};

  /**
   * a ping consist of a send ping and a receive pong
   */
  async ping(){
    await this.sendPacket("Ping");
    return await this.awaitPackage("Pong");
  }

  async sendPacket(packetType) { /*...*/ }
  
  /**
   * This expects a specific packet type to be received in the future
   * @param {*} packetType 
   */
  awaitPackage(packetType) {
    return new Promise((resolve, reject) => {
      this.awaitedPacketTypes[packetType] = {
        resolve,
        reject
      };
    });
  }

  /**
   * This gets called for every packet from the network side and calls the correct resolver if something waits for this packet type
   * @param {*} packet 
   */
  onIncomingPacket(packet) {
    if(this.awaitedPacketTypes[packet.type]) {
      this.awaitedPacketTypes[packet.type].resolve(packet);
      this.awaitedPacketTypes[packet.type] = undefined;
    } else {
      /*...*/
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

Mas*_*inn 5

或者更清楚地说:我可以以某种方式重新创建awaitPackage + onIncomingPacket 的resolve() 回调函数行为吗?

有点?Rust Future 只是“可以轮询是否准备就绪的东西”,它是一个比 JS Promise 低得多的概念。

有些库声称提供 JS 风格的 Promise,但大多数异步库可能提供一个名称不同的类似对象,例如在 Tokio 中,您可能需要一个oneshot 通道,即可以发送单个值的通道,导致如下结果:

struct Packet { r#type: &'static str }
struct Client {
  awaited: Mutex<HashMap<&'static str, Sender<Packet>>>
}

impl Client {
    async fn ping(&self) -> Packet {
        self.send_packet("Pong").await;
        self.await_package("Pong").await.unwrap()
    }
    async fn send_packet(&self, _: &'static str) {}
    fn await_package(&self, packet_type: &'static str) -> Receiver<Packet> {
        let (tx, rx) = channel();
        self.awaited.lock().unwrap().insert(packet_type, tx);
        rx
    }
    fn on_incoming_packet(&self, packet: Packet) {
        if let Some(tx) = self.awaited.lock().unwrap().remove(packet.r#type) {
            tx.send(packet);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)