1use core::error::Error;
2use core::marker::PhantomData;
3use core::task::Poll;
4
5use futures_core::Stream;
6
7use crate::js_types::JsValue;
8use crate::{link::RpcCellAM, serialize::UseInJsCodeWriter, Browser, UseInJsCode};
9
10use crate::protocol::REPLY;
11use core::fmt::Write;
12pin_project_lite::pin_project! {
13
14pub struct RpcHandle<C> {
15 #[pin]
16 pub(crate) recv: RpcCellAM,
17 pub(crate) browser: Browser,
18 pub(crate) data: C,
19}
20}
21pub struct Reply<C> {
22 pub(crate) phantom: PhantomData<C>,
23 pub(crate) id: u64,
24}
25impl<C: UseInJsCode> RpcHandle<Reply<C>> {
26 pub fn reply(self, c: C) {
27 let mut link = self.browser.0.lock();
28 let id = self.data.id;
29 writeln!(
30 link.raw_commands_buf(),
31 "{REPLY}({id},{})",
32 UseInJsCodeWriter(&c)
33 )
34 .unwrap();
35 link.wake_outgoing_lazy();
36 }
37}
38pub struct Request<T, C> {
39 pub(crate) reply: Reply<C>,
40 pub(crate) data: T,
41}
42impl<C: UseInJsCode, T> RpcHandle<Request<T, C>> {
43 pub fn decaps(self) -> (T, RpcHandle<Reply<C>>) {
44 (
45 self.data.data,
46 RpcHandle {
47 recv: self.recv,
48 browser: self.browser,
49 data: self.data.reply,
50 },
51 )
52 }
53}
54pub struct Endpoint<T, C> {
55 pub(crate) phantom: PhantomData<(T, C)>,
56}
57pub struct Lock {
58 nope: (),
59}
60pub trait RpcDeserialize: Sized {
61 fn deser<'a>(
62 a: &'a str,
63 browser: &Browser,
64 recv: &RpcCellAM,
65 lock: &Lock,
66 ) -> Result<(Self, &'a str), ()>;
67}
68impl RpcDeserialize for () {
69 fn deser<'a>(
70 a: &'a str,
71 browser: &Browser,
72 recv: &RpcCellAM,
73 lock: &Lock,
74 ) -> Result<(Self, &'a str), ()> {
75 Ok(((), a))
76 }
77}
78impl<A: RpcDeserialize, B: RpcDeserialize> RpcDeserialize for (A, B) {
79 fn deser<'a>(
80 a: &'a str,
81 browser: &Browser,
82 recv: &RpcCellAM,
83 lock: &Lock,
84 ) -> Result<(Self, &'a str), ()> {
85 let (v0, a) = A::deser(a, browser, recv, lock)?;
86 let (v1, a) = B::deser(a, browser, recv, lock)?;
87 Ok(((v0, v1), a))
88 }
89}
90impl RpcDeserialize for u64 {
91 fn deser<'a>(
92 a: &'a str,
93 browser: &Browser,
94 recv: &RpcCellAM,
95 lock: &Lock,
96 ) -> Result<(Self, &'a str), ()> {
97 let Some((s, a)) = a.split_once(";") else {
98 return Err(());
99 };
100 let Ok(v) = u64::from_str_radix(s, 10) else {
101 return Err(());
102 };
103 return Ok((v, a));
104 }
105}
106impl RpcDeserialize for JsValue {
107 fn deser<'a>(
108 a: &'a str,
109 browser: &Browser,
110 recv: &RpcCellAM,
111 lock: &Lock,
112 ) -> Result<(Self, &'a str), ()> {
113 let (v, a) = u64::deser(a, browser, recv, lock)?;
114 return Ok((
115 JsValue {
116 id: v,
117 browser: browser.clone(),
118 },
119 a,
120 ));
121 }
122}
123impl<C: UseInJsCode, T: RpcDeserialize> Stream for RpcHandle<Endpoint<T, C>> {
124 type Item = RpcHandle<Request<T, C>>;
125
126 fn poll_next(
127 self: core::pin::Pin<&mut Self>,
128 cx: &mut core::task::Context<'_>,
129 ) -> core::task::Poll<Option<Self::Item>> {
130 let (browser, recv) = (self.browser.clone(), self.recv.clone());
131 let mut project = self.project();
132 loop {
133 let Poll::Ready(a) = project.recv.as_mut().poll_next(cx) else {
134 return Poll::Pending;
135 };
136 let Some(a) = a else {
137 return Poll::Ready(None);
138 };
139 let Ok(((r, a), _)) =
140 RpcDeserialize::deser(a.as_str(), &browser, &recv, &Lock { nope: () })
141 else {
142 continue;
143 };
144 return Poll::Ready(Some(RpcHandle {
145 recv: recv,
146 browser: browser,
147 data: Request {
148 reply: Reply {
149 phantom: PhantomData,
150 id: r,
151 },
152 data: a,
153 },
154 }));
155 }
156 }
157}
158#[macro_export]
159macro_rules! wrap {
160 ([$($g:tt)*] as $e:expr => $ty:ty) => {
161 impl $($g)* $crate::RpcDeserialize for $ty{
162 fn deser<'a>(
163 a: &'a str,
164 browser: &$crate::Browser,
165 recv: &$crate::RpcCellAM,
166 lock: &$crate::Lock,
167 ) -> Result<(Self, &'a str), ()> {
168 let (v,a) = $crate::RpcDeserialize::deser(a,browser,recv,lock)?;
169 Ok(($e(v),a))
170 }
171 }
172 };
173}