Patchwork D8442: rust-chg: reimplement attach_io operation as async function

login
register
mail settings
Submitter phabricator
Date April 16, 2020, 12:30 p.m.
Message ID <differential-rev-PHID-DREV-f7tjl7jcbrzjkyzpjevq-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/46146/
State Superseded
Headers show

Comments

phabricator - April 16, 2020, 12:30 p.m.
yuja created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  In short, MessageLoop<Connection> was redesigned as Protocol<Connection>,
  and the protocol methods no longer consume self.
  
  API changes are briefly documented in the following page:
  https://docs.rs/tokio-hglib/0.3.0/tokio_hglib/struct.Protocol.html

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D8442

AFFECTED FILES
  rust/chg/src/attachio.rs
  rust/chg/src/lib.rs

CHANGE DETAILS




To: yuja, #hg-reviewers
Cc: mercurial-devel
phabricator - April 17, 2020, 11:58 a.m.
Alphare added a comment.
Alphare accepted this revision.


  It's impressive how easier to reason about this all becomes.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8442/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8442

To: yuja, #hg-reviewers, Alphare
Cc: Alphare, mercurial-devel

Patch

diff --git a/rust/chg/src/lib.rs b/rust/chg/src/lib.rs
--- a/rust/chg/src/lib.rs
+++ b/rust/chg/src/lib.rs
@@ -3,7 +3,7 @@ 
 // This software may be used and distributed according to the terms of the
 // GNU General Public License version 2 or any later version.
 
-//mod attachio;
+mod attachio;
 //mod clientext;
 //pub mod locator;
 pub mod message;
diff --git a/rust/chg/src/attachio.rs b/rust/chg/src/attachio.rs
--- a/rust/chg/src/attachio.rs
+++ b/rust/chg/src/attachio.rs
@@ -5,17 +5,15 @@ 
 
 //! Functions to send client-side fds over the command server channel.
 
-use futures::{try_ready, Async, Future, Poll};
 use std::io;
 use std::os::unix::io::AsRawFd;
 use tokio_hglib::codec::ChannelMessage;
-use tokio_hglib::protocol::MessageLoop;
-use tokio_hglib::{Client, Connection};
+use tokio_hglib::{Connection, Protocol};
 
 use crate::message;
 use crate::procutil;
 
-/// Future to send client-side fds over the command server channel.
+/// Sends client-side fds over the command server channel.
 ///
 /// This works as follows:
 /// 1. Client sends "attachio" request.
@@ -26,58 +24,21 @@ 
 /// If the stderr is omitted, it will be redirected to the stdout. This
 /// allows us to attach the pager stdin to both stdout and stderr, and
 /// dispose of the client-side handle once attached.
-#[must_use = "futures do nothing unless polled"]
-pub struct AttachIo<C, I, O, E>
-where
-    C: Connection,
-{
-    msg_loop: MessageLoop<C>,
-    stdin: I,
-    stdout: O,
-    stderr: Option<E>,
-}
-
-impl<C, I, O, E> AttachIo<C, I, O, E>
-where
-    C: Connection + AsRawFd,
-    I: AsRawFd,
-    O: AsRawFd,
-    E: AsRawFd,
-{
-    pub fn with_client(
-        client: Client<C>,
-        stdin: I,
-        stdout: O,
-        stderr: Option<E>,
-    ) -> AttachIo<C, I, O, E> {
-        let msg_loop = MessageLoop::start(client, b"attachio");
-        AttachIo {
-            msg_loop,
-            stdin,
-            stdout,
-            stderr,
-        }
-    }
-}
-
-impl<C, I, O, E> Future for AttachIo<C, I, O, E>
-where
-    C: Connection + AsRawFd,
-    I: AsRawFd,
-    O: AsRawFd,
-    E: AsRawFd,
-{
-    type Item = Client<C>;
-    type Error = io::Error;
-
-    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
+pub async fn attach_io(
+    proto: &mut Protocol<impl Connection + AsRawFd>,
+    stdin: impl AsRawFd,
+    stdout: impl AsRawFd,
+    stderr: Option<impl AsRawFd>,
+) -> io::Result<()> {
+    // TODO: unindent
+    {
+        proto.send_command("attachio").await?;
         loop {
-            let (client, msg) = try_ready!(self.msg_loop.poll());
-            match msg {
+            match proto.fetch_response().await? {
                 ChannelMessage::Data(b'r', data) => {
                     let fd_cnt = message::parse_result_code(data)?;
                     if fd_cnt == 3 {
-                        return Ok(Async::Ready(client));
+                        return Ok(());
                     } else {
                         return Err(io::Error::new(
                             io::ErrorKind::InvalidData,
@@ -87,18 +48,16 @@ 
                 }
                 ChannelMessage::Data(..) => {
                     // just ignore data sent to uninteresting (optional) channel
-                    self.msg_loop = MessageLoop::resume(client);
                 }
                 ChannelMessage::InputRequest(1) => {
                     // this may fail with EWOULDBLOCK in theory, but the
                     // payload is quite small, and the send buffer should
                     // be empty so the operation will complete immediately
-                    let sock_fd = client.as_raw_fd();
-                    let ifd = self.stdin.as_raw_fd();
-                    let ofd = self.stdout.as_raw_fd();
-                    let efd = self.stderr.as_ref().map_or(ofd, |f| f.as_raw_fd());
+                    let sock_fd = proto.as_raw_fd();
+                    let ifd = stdin.as_raw_fd();
+                    let ofd = stdout.as_raw_fd();
+                    let efd = stderr.as_ref().map_or(ofd, |f| f.as_raw_fd());
                     procutil::send_raw_fds(sock_fd, &[ifd, ofd, efd])?;
-                    self.msg_loop = MessageLoop::resume(client);
                 }
                 ChannelMessage::InputRequest(..)
                 | ChannelMessage::LineRequest(..)