1use crate::response;
2use erased_serde::Serialize as ErasedSerialize;
3use serde::de::DeserializeOwned;
4use serde::ser::SerializeStruct;
5use serde::Serialize;
6use std::marker::PhantomData;
7
8pub trait ApiCall: sealed::Sealed {
9 const KIND: &str;
10 type Response: DeserializeOwned + 'static;
11}
12
13#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
14pub struct Call<T>(T);
15
16impl<T: ApiCall + Serialize> Call<T> {
17 pub fn new(data: T) -> Self {
18 Self(data)
19 }
20}
21
22impl<T: ApiCall + Serialize> Serialize for Call<T> {
23 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
24 where
25 S: serde::Serializer,
26 {
27 let zst = std::mem::size_of::<T>() == 0;
28 let len = if zst { 1 } else { 2 };
29
30 let mut s = serializer.serialize_struct("RpcCall", len)?;
31
32 s.serialize_field("type", T::KIND)?;
33
34 if !zst {
35 s.serialize_field("data", &self.0)?;
36 }
37
38 s.end()
39 }
40}
41
42impl Call<List> {
43 pub fn list() -> Self {
44 Self(List)
45 }
46}
47
48impl Call<Methods> {
49 pub fn methods(device_id: uuid::Uuid) -> Self {
50 Self(Methods { device_id })
51 }
52}
53
54impl<'a, R: DeserializeOwned + 'static> Call<Invoke<'a, R>> {
55 pub fn invoke(
56 device_id: uuid::Uuid,
57 method_name: &'a str,
58 parameters: &'a [&'a dyn ErasedSerialize],
59 ) -> Self {
60 Self(Invoke {
61 device_id,
62 name: method_name,
63 parameters,
64 _ret_value: PhantomData,
65 })
66 }
67}
68
69#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Serialize)]
70pub struct List;
71
72impl ApiCall for List {
73 const KIND: &'static str = "list";
74 type Response = response::List;
75}
76
77#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Serialize)]
78#[serde(transparent)]
79pub struct Methods {
80 #[serde(rename = "deviceId")]
81 pub device_id: uuid::Uuid,
82}
83
84impl ApiCall for Methods {
85 const KIND: &'static str = "methods";
86 type Response = response::Methods;
87}
88
89#[derive(Copy, Clone, Default, Serialize)]
90#[serde(rename_all = "camelCase")]
91pub struct Invoke<'a, R> {
92 pub device_id: uuid::Uuid,
93 pub name: &'a str,
94 pub parameters: &'a [&'a dyn ErasedSerialize],
95 _ret_value: PhantomData<fn() -> R>,
97}
98
99impl<R: DeserializeOwned + 'static> ApiCall for Invoke<'_, R> {
100 const KIND: &'static str = "invoke";
101 type Response = response::Return<R>;
102}
103
104mod sealed {
105 use serde::de::DeserializeOwned;
106
107 use super::{Invoke, List, Methods};
108
109 pub trait Sealed {}
110
111 impl Sealed for List {}
112 impl Sealed for Methods {}
113 impl<R: DeserializeOwned + 'static> Sealed for Invoke<'_, R> {}
114}