use std::cell::Cell;
use std::cell::UnsafeCell;
use std::future::Future;
use std::mem;
use std::ptr::NonNull;
use std::task::Context;
use std::task::Poll;
use async_trait::async_trait;
mod de;
#[async_trait(?Send)]
pub trait Run<'de, E> {
type Output: 'de;
async fn run<'s>(
self,
instructor: Instructor<'s, 'de>,
) -> Result<Self::Output, E>;
}
pub struct Executor<D> {
deserializer: D,
}
impl<'de, D: serde::Deserializer<'de>> Executor<D> {
pub fn new(deserializer: D) -> Self {
Self {
deserializer,
}
}
pub fn run<R: Run<'de, E>, E>(self, r: R) -> Result<R::Output, E>
where
E: From<D::Error>,
{
let deserializer = self.deserializer;
let state = State {
internal_op: Cell::new(None),
data: UnsafeCell::new(Data::None),
depth: Cell::new(0),
expected_depth: Cell::new(0),
deserialize: Cell::new(None),
visit: Cell::new(None),
};
let fut = r.run(Instructor {
state: &state,
cloned: false,
depth: 0,
});
match <de::Bridge<'_, '_, _> as serde::de::DeserializeSeed<'_>>::deserialize(
de::Bridge {
state: &state,
fut: fut,
},
deserializer,
)? {
Poll::Pending => unreachable!(),
Poll::Ready(result) => result,
}
}
}
pub struct SeqInstructor<'s, 'de> {
state: &'s State<'de>,
cloned: bool,
depth: usize,
}
#[derive(Debug)]
pub struct Instructor<'s, 'de> {
state: &'s State<'de>,
cloned: bool,
depth: usize,
}
impl<'s, 'de> SeqInstructor<'s, 'de> {
pub fn cloned(&mut self) -> Self {
self.cloned = true;
Self {
state: self.state,
cloned: self.cloned,
depth: self.depth,
}
}
pub fn ask(
&mut self,
deserialize: Deserialize,
) -> Result<impl Future<Output=Step<'s, 'de>> + '_, Option<Deserialize>> {
if self.state.depth.get() != self.depth {
panic!("wrong depth");
}
let internal_op = self.state.internal_op.get();
match internal_op {
None => {},
_ => todo!()
}
let current = self.state.deserialize.get();
match (current, deserialize) {
(Some(current), visit) if current == visit => {},
(Some(current), _) => {
return Err(Some(current))
},
_ => {},
}
self.state.deserialize.set(Some(deserialize));
Ok(futures::future::poll_fn(move |_cx: &mut Context<'_>| {
self.state.expected_depth.set(self.depth);
match self.state.visit.get() {
None => Poll::Pending,
Some(_) => {
Poll::Ready(Step {
state: self.state,
cloned: self.cloned,
depth: self.depth + 1,
})
},
}
}))
}
}
impl<'s, 'de> Instructor<'s, 'de> {
pub fn cloned(&mut self) -> Self {
self.cloned = true;
Self {
state: self.state,
cloned: self.cloned,
depth: self.depth,
}
}
pub fn ask(
self,
deserialize: Deserialize,
) -> Result<impl Future<Output=Step<'s, 'de>>, (Self, Deserialize)> {
if self.state.depth.get() != self.depth {
panic!("wrong depth");
}
let current = self.state.deserialize.get();
match (current, deserialize) {
(Some(current), visit) if current == visit => {},
(Some(current), _) => {
return Err((self, current))
},
_ => {},
}
self.state.deserialize.set(Some(deserialize));
Ok(futures::future::poll_fn(move |_cx: &mut Context<'_>| {
self.state.expected_depth.set(self.depth);
match self.state.visit.get() {
None => Poll::Pending,
Some(_) => {
Poll::Ready(Step {
state: self.state,
cloned: self.cloned,
depth: self.depth + 1,
})
},
}
}))
}
}
#[derive(Debug)]
pub struct Step<'s, 'de> {
state: &'s State<'de>,
cloned: bool,
depth: usize,
}
impl<'s, 'de> Step<'s, 'de> {
pub fn kind(&self) -> Visit {
if self.state.depth.get() != self.depth {
panic!("Wrong depth");
}
self.state.visit.get().expect("Must not be called after call to ask")
}
pub fn cloned(&mut self) -> Self {
self.cloned = true;
Self {
state: self.state,
cloned: self.cloned,
depth: self.depth,
}
}
pub fn inspect_string<F, R>(self, f: F) -> Option<R>
where
F: for<'a> FnOnce(Inspect<'a, 'de, str>) -> R
{
if matches!(self.kind(), Visit::Str) {
let data = self.state.data.get();
match unsafe { &*data } {
Data::DeStr(s) => {
return Some(f(Inspect::Borrowed(s)));
},
Data::String(ref s) if self.cloned => {
return Some(f(Inspect::Buffered(&**s)));
},
Data::Str(s) => {
return Some(f(Inspect::Buffered(unsafe { s.as_ref() })));
},
Data::String(_) => {
},
_ => unreachable!(),
}
let s = mem::replace(unsafe { &mut *data }, Data::None);
if let Data::String(s) = s {
Some(f(Inspect::Owned(s)))
} else {
unreachable!()
}
} else {
None
}
}
pub fn inspect_bytes<F, R>(self, f: F) -> Option<R>
where
F: for<'a> FnOnce(Inspect<'a, 'de, [u8]>) -> R
{
if matches!(self.kind(), Visit::Bytes) {
let data = self.state.data.get();
match unsafe { &*data } {
Data::DeBytes(s) => {
return Some(f(Inspect::Borrowed(s)));
},
Data::ByteBuf(ref s) if self.cloned => {
return Some(f(Inspect::Buffered(&**s)));
},
Data::Bytes(s) => {
return Some(f(Inspect::Buffered(unsafe { s.as_ref() })));
},
Data::ByteBuf(_) => {
},
_ => unreachable!(),
}
let s = mem::replace(unsafe { &mut *data }, Data::None);
if let Data::ByteBuf(s) = s {
Some(f(Inspect::Owned(s)))
} else {
unreachable!()
}
} else {
None
}
}
pub fn inspect_seq<Fun, Fut, R>(
self,
f: Fun,
) -> Option<impl Future<Output=R>>
where
Fun: FnOnce(SeqInstructor<'s, 'de>) -> Fut,
Fut: Future<Output=R> + 's + 'de,
{
if matches!(self.kind(), Visit::Seq) {
Some(async {
todo!()
})
} else {
None
}
}
}
pub enum Inspect<'a, 'de, T: ?Sized> {
Borrowed(&'de T),
Buffered(&'a T),
Owned(Box<T>),
}
#[derive(Debug)]
struct State<'de> {
internal_op: Cell<Option<InternalOp>>,
visit: Cell<Option<Visit>>,
deserialize: Cell<Option<Deserialize>>,
depth: Cell<usize>,
expected_depth: Cell<usize>,
data: UnsafeCell<Data<'de>>,
}
enum Data<'de> {
DeStr(&'de str),
String(Box<str>),
Str(NonNull<str>),
DeBytes(&'de [u8]),
ByteBuf(Box<[u8]>),
Bytes(NonNull<[u8]>),
None
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Visit {
Bool(bool),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
F32(f32),
F64(f64),
Char(char),
Some,
None,
Unit,
Seq,
Map,
NewtypeStruct,
Enum,
Str,
Bytes,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Deserialize {
Any,
IgnoredAny,
Bool,
I8,
I16,
I32,
I64,
I128,
U8,
U16,
U32,
U64,
U128,
F32,
F64,
Char,
Option,
Unit,
Seq,
Map,
Identifier,
Bytes,
ByteBuf, Str,
String, Tuple(usize),
UnitStruct {
name: &'static str
},
TupleStruct {
name: &'static str,
len: usize,
},
NewtypeStruct {
name: &'static str,
},
Struct {
name: &'static str,
fields: &'static [&'static str],
},
Enum {
name: &'static str,
variants: &'static [&'static str],
},
}
#[derive(Copy, Clone, Debug)]
enum InternalOp {
SizeHintReq,
SizeHintRes(Option<usize>)
}