Last active
February 26, 2024 18:01
-
-
Save oscartbeaumont/1c7c4bea577d7579faf57600a427429b to your computer and use it in GitHub Desktop.
Content Types Idea
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "testing" | |
version = "0.1.0" | |
edition = "2021" | |
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
[dependencies] | |
erased-serde = "0.4.3" | |
pin-project-lite = "0.2.13" | |
serde = { version = "1.0.197", features = ["derive"] } | |
serde_json = "1.0.114" | |
tokio = { version = "1.36.0", features = ["macros", "rt-multi-thread"] } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{ | |
future::{poll_fn, Future}, | |
pin::Pin, | |
task::{Context, Poll}, | |
}; | |
use pin_project_lite::pin_project; | |
use serde::{Serialize, Serializer}; | |
#[tokio::main] | |
async fn main() { | |
let p: Procedure = Box::new(|| { | |
Box::pin(ProcedureResult { | |
handler: async { 42 }, | |
value: None, | |
}) | |
}); | |
let result = execute(&p, serde_json::value::Serializer).await.unwrap(); | |
println!("{result:?}"); | |
let mut buf = Vec::new(); | |
execute(&p, &mut serde_json::Serializer::new(&mut buf)) | |
.await | |
.unwrap(); | |
println!("{:?}", String::from_utf8_lossy(&buf)); | |
} | |
async fn execute<S: Serializer>(procedure: &Procedure, serializer: S) -> Result<S::Ok, S::Error> { | |
let mut serializer = Some(serializer); | |
let mut fut = (procedure)(); | |
poll_fn(move |cx| { | |
fut.as_mut() | |
.poll(cx) | |
.map(|res| res.serialize(serializer.take().expect("Future yielded more than once"))) | |
}) | |
.await | |
} | |
type Procedure = Box<dyn Fn() -> Pin<Box<dyn AnyProcedureResult>>>; | |
// Can't be `Future` due to lack of GAT on `Output`. | |
pub trait AnyProcedureResult { | |
fn poll<'a>( | |
self: Pin<&'a mut Self>, | |
cx: &mut Context<'_>, | |
) -> Poll<&'a dyn erased_serde::Serialize>; | |
} | |
pin_project! { | |
pub struct ProcedureResult<TResult, F: Future<Output = TResult>> { | |
#[pin] | |
handler: F, | |
#[pin] | |
value: Option<TResult>, | |
} | |
} | |
impl<TResult: serde::Serialize + Unpin, F: Future<Output = TResult>> AnyProcedureResult | |
for ProcedureResult<TResult, F> | |
{ | |
fn poll<'a>( | |
mut self: Pin<&'a mut Self>, | |
cx: &mut Context<'_>, | |
) -> Poll<&'a dyn erased_serde::Serialize> { | |
let mut this = self.as_mut().project(); | |
match this.handler.poll(cx) { | |
Poll::Ready(value) => { | |
*this.value = Some(value); | |
// SAFETY: `value` of type `TResult` is `Unpin`. | |
let this = unsafe { | |
let v = self.get_unchecked_mut(); | |
&v.value | |
}; | |
Poll::Ready(this.as_ref().expect("set above")) | |
} | |
Poll::Pending => Poll::Pending, | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment