From 781f0d1d09ade855f84d7fa8d3cc8f769e1c4fc4 Mon Sep 17 00:00:00 2001 From: Jisu-Woniu <31986081+Jisu-Woniu@users.noreply.github.com> Date: Sat, 2 Mar 2024 16:29:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=9A=A7=20try=20adding=20AsyncComp?= =?UTF-8?q?arer=20to=20replace=20async-trait?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 1 + crates/rsjudge-judger/Cargo.toml | 5 +- crates/rsjudge-judger/src/comparer/compare.rs | 73 +++++++++++++++++++ crates/rsjudge-judger/src/comparer/mod.rs | 47 ++++++++++++ crates/rsjudge-judger/src/default_comparer.rs | 1 - crates/rsjudge-judger/src/lib.rs | 19 +---- 6 files changed, 126 insertions(+), 20 deletions(-) create mode 100644 crates/rsjudge-judger/src/comparer/compare.rs create mode 100644 crates/rsjudge-judger/src/comparer/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 3e65478..026a86a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1068,6 +1068,7 @@ name = "rsjudge-judger" version = "0.1.0" dependencies = [ "async-trait", + "pin-project", "temp-dir", "tokio", "tokio-stream", diff --git a/crates/rsjudge-judger/Cargo.toml b/crates/rsjudge-judger/Cargo.toml index 035f889..043832d 100644 --- a/crates/rsjudge-judger/Cargo.toml +++ b/crates/rsjudge-judger/Cargo.toml @@ -8,9 +8,10 @@ rust-version.workspace = true [dependencies] async-trait = "0.1.77" -tokio = { version = "1.36.0", features = ["io-util", "fs"] } +pin-project = "1.1.4" +tokio = { version = "1.36.0", features = ["io-util", "fs", "macros"] } tokio-stream = { version = "0.1.14", features = ["io-util", "tokio-util"] } [dev-dependencies] temp-dir = "0.1.12" -tokio = { version = "1.36.0", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.36.0", features = ["rt-multi-thread"] } diff --git a/crates/rsjudge-judger/src/comparer/compare.rs b/crates/rsjudge-judger/src/comparer/compare.rs new file mode 100644 index 0000000..d86ce01 --- /dev/null +++ b/crates/rsjudge-judger/src/comparer/compare.rs @@ -0,0 +1,73 @@ +use std::{ + future::Future, + io, + marker::PhantomPinned, + pin::Pin, + task::{ready, Context, Poll}, +}; + +use pin_project::pin_project; +use tokio::io::AsyncRead; + +use super::AsyncComparer; +use crate::CompareResult; + +#[derive(Debug)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +#[pin_project] +pub struct Compare<'a, C: ?Sized, Out, Ans> { + comparer: &'a mut C, + out: Out, + ans: Ans, + + // Make this future `!Unpin` for compatibility with async trait methods. + #[pin] + _pin: PhantomPinned, +} + +pub(super) fn compare<'a, C, Out, Ans>( + comparer: &'a mut C, + out: Out, + ans: Ans, +) -> Compare<'a, C, Out, Ans> +where + C: AsyncComparer + Unpin + ?Sized, + Out: AsyncRead + Unpin, + Ans: AsyncRead + Unpin, +{ + Compare { + comparer, + out, + ans, + _pin: PhantomPinned, + } +} + +fn compare_internal( + mut comparer: Pin<&mut C>, + cx: &mut Context, + out: Out, + ans: Ans, +) -> Poll> +where + C: AsyncComparer + Unpin + ?Sized, + Out: AsyncRead + Unpin, + Ans: AsyncRead + Unpin, +{ + Poll::Ready(ready!(comparer.as_mut().poll_compare(cx, out, ans))) +} + +impl<'c, C, Out, Ans> Future for Compare<'c, C, Out, Ans> +where + C: AsyncComparer + Unpin + ?Sized, + Out: AsyncRead + Unpin, + Ans: AsyncRead + Unpin, +{ + type Output = io::Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let me = self.project(); + + compare_internal(Pin::new(*me.comparer), cx, me.out, me.ans) + } +} diff --git a/crates/rsjudge-judger/src/comparer/mod.rs b/crates/rsjudge-judger/src/comparer/mod.rs new file mode 100644 index 0000000..0fd0b33 --- /dev/null +++ b/crates/rsjudge-judger/src/comparer/mod.rs @@ -0,0 +1,47 @@ +pub mod compare; +use std::{ + pin::Pin, + task::{Context, Poll}, +}; + +use async_trait::async_trait; +use tokio::io::{self, AsyncRead}; + +use self::compare::{compare, Compare}; + +#[derive(Debug, PartialEq)] +pub enum CompareResult { + Accepted, + WrongAnswer, + PresentationError, +} + +// TODO: Migrate to AsyncComparer trait +#[async_trait] +pub trait Comparer { + async fn compare(&self, out: Out, ans: Ans) -> io::Result + where + Out: AsyncRead + Send + Unpin, + Ans: AsyncRead + Send + Unpin; +} + +pub trait AsyncComparer { + fn poll_compare( + self: Pin<&mut Self>, + cx: &mut Context, + out: Out, + ans: Ans, + ) -> Poll> + where + Out: AsyncRead + Unpin, + Ans: AsyncRead + Unpin; + + fn compare<'a, Out, Ans>(&'a mut self, out: Out, ans: Ans) -> Compare<'a, Self, Out, Ans> + where + Self: Unpin, + Out: AsyncRead + Send + Unpin, + Ans: AsyncRead + Send + Unpin, + { + compare(self, out, ans) + } +} diff --git a/crates/rsjudge-judger/src/default_comparer.rs b/crates/rsjudge-judger/src/default_comparer.rs index 7a7a120..0a862b8 100644 --- a/crates/rsjudge-judger/src/default_comparer.rs +++ b/crates/rsjudge-judger/src/default_comparer.rs @@ -46,7 +46,6 @@ impl Comparer for DefaultComparer { let out = BufReader::new(out); let ans = BufReader::new(ans); - // LinesStream::new(out.lines()) let mut out_lines = LinesStream::new(out.lines()); let mut ans_lines = LinesStream::new(ans.lines()); diff --git a/crates/rsjudge-judger/src/lib.rs b/crates/rsjudge-judger/src/lib.rs index 4cff28a..711483b 100644 --- a/crates/rsjudge-judger/src/lib.rs +++ b/crates/rsjudge-judger/src/lib.rs @@ -1,19 +1,4 @@ -use async_trait::async_trait; -use tokio::io::{self, AsyncRead}; +pub mod comparer; pub mod default_comparer; -#[derive(Debug, PartialEq)] -pub enum CompareResult { - Accepted, - WrongAnswer, - PresentationError, -} - -// TODO: Add `Compare` type and mannually implement `Future` trait for it. -#[async_trait] -pub trait Comparer { - async fn compare(&self, out: Out, ans: Ans) -> io::Result - where - Out: AsyncRead + Send + Unpin, - Ans: AsyncRead + Send + Unpin; -} +pub use comparer::{CompareResult, Comparer};