px_wsdom_core/
rpc.rs

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}