oc2_hlapi/
call.rs

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    // Unused, but this is required for the API for RpcResponse to be the way I'd like it.
96    _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}