perspective_server/
ffi.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
5// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13#[repr(C, packed)]
14pub struct CppResponse {
15    data_ptr: usize,
16    length: u32,
17    client_id: u32,
18}
19
20#[repr(C, packed)]
21pub struct CppResponseBatch {
22    length: u32,
23    entries_ptr: usize,
24}
25
26unsafe extern "C" {
27    fn psp_alloc(size: usize) -> *mut u8;
28    fn psp_free(ptr: *const u8);
29    fn psp_new_server(realtime_mode: bool) -> *const u8;
30    fn psp_new_session(server: *const u8) -> u32;
31    fn psp_delete_server(server: *const u8);
32    fn psp_handle_request(
33        server: *const u8,
34        client_id: u32,
35        buffer_ptr: *const u8,
36        buffer_len: usize,
37    ) -> ResponseBatch;
38    fn psp_poll(server: *const u8) -> ResponseBatch;
39    fn psp_close_session(server: *const u8, client_id: u32);
40    fn psp_num_cpus() -> i32;
41    fn psp_set_num_cpus(num_cpus: i32);
42}
43
44pub fn num_cpus() -> i32 {
45    unsafe { psp_num_cpus() }
46}
47
48pub fn set_num_cpus(num_cpus: i32) {
49    unsafe { psp_set_num_cpus(num_cpus) }
50}
51
52pub struct Response(*const CppResponse);
53
54impl Response {
55    pub fn msg(&self) -> &[u8] {
56        let resp = unsafe { &*self.0 };
57        let data_ptr = resp.data_ptr as *const u8;
58        let len = resp.length as usize;
59        unsafe { std::slice::from_raw_parts(data_ptr, len) }
60    }
61
62    pub fn client_id(&self) -> u32 {
63        let resp = unsafe { &*self.0 };
64        resp.client_id
65    }
66}
67
68impl Drop for Response {
69    fn drop(&mut self) {
70        unsafe {
71            let resp = &*self.0;
72            psp_free(resp.data_ptr as *const u8);
73        }
74    }
75}
76
77#[repr(transparent)]
78pub struct ResponseBatch(*const CppResponseBatch);
79
80impl ResponseBatch {
81    pub fn size(&self) -> usize {
82        let batch = unsafe { &*self.0 };
83        batch.length as usize
84    }
85
86    pub fn iter_responses(&self) -> impl Iterator<Item = Response> + Send + Sync {
87        let batch = unsafe { &*self.0 };
88        let num_responses = batch.length;
89        (0..num_responses).map(move |idx| {
90            let entries_ptr = batch.entries_ptr as *const CppResponse;
91            Response(unsafe { entries_ptr.offset(idx as isize) })
92        })
93    }
94}
95
96impl Drop for ResponseBatch {
97    fn drop(&mut self) {
98        unsafe {
99            let batch = &*self.0;
100            psp_free(batch.entries_ptr as *const u8);
101            psp_free(self.0 as *const u8)
102        }
103    }
104}
105
106pub struct Request(*const u8, usize);
107
108impl From<&[u8]> for Request {
109    fn from(value: &[u8]) -> Self {
110        let len = value.len();
111        let ptr = unsafe { psp_alloc(len) };
112        unsafe { std::ptr::copy(std::ptr::addr_of!(value[0]), ptr, len) };
113        Request(ptr, len)
114    }
115}
116
117impl Drop for Request {
118    fn drop(&mut self) {
119        unsafe {
120            psp_free(self.0);
121        };
122    }
123}
124
125pub struct Server(*const u8);
126
127impl Server {
128    pub fn new(realtime_mode: bool) -> Self {
129        Server(unsafe { psp_new_server(realtime_mode) })
130    }
131
132    pub fn new_session(&self) -> u32 {
133        unsafe { psp_new_session(self.0) }
134    }
135
136    pub fn handle_request(&self, client_id: u32, request: &Request) -> ResponseBatch {
137        unsafe { psp_handle_request(self.0, client_id, request.0, request.1) }
138    }
139
140    pub fn poll(&self) -> ResponseBatch {
141        unsafe { psp_poll(self.0) }
142    }
143
144    pub fn close_session(&self, session_id: u32) {
145        unsafe { psp_close_session(self.0, session_id) }
146    }
147}
148
149impl Drop for Server {
150    fn drop(&mut self) {
151        unsafe { psp_delete_server(self.0) }
152    }
153}
154
155unsafe impl Send for Server {}
156unsafe impl Sync for Server {}
157
158unsafe impl Send for Request {}
159unsafe impl Sync for Request {}
160
161unsafe impl Send for ResponseBatch {}
162unsafe impl Sync for ResponseBatch {}
163
164unsafe impl Send for Response {}
165unsafe impl Sync for Response {}