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
44/// Returns the number of threads the internal threadpool will use.
45pub fn num_cpus() -> i32 {
46    unsafe { psp_num_cpus() }
47}
48
49/// Set the number of threads the internal threadpool will use. Can also be set
50/// with `NUM_OMP_THREADS` environment variable.
51pub fn set_num_cpus(num_cpus: i32) {
52    unsafe { psp_set_num_cpus(num_cpus) }
53}
54
55pub struct Response(*const CppResponse);
56
57impl Response {
58    pub fn msg(&self) -> &[u8] {
59        let resp = unsafe { &*self.0 };
60        let data_ptr = resp.data_ptr as *const u8;
61        let len = resp.length as usize;
62        unsafe { std::slice::from_raw_parts(data_ptr, len) }
63    }
64
65    pub fn client_id(&self) -> u32 {
66        let resp = unsafe { &*self.0 };
67        resp.client_id
68    }
69}
70
71impl Drop for Response {
72    fn drop(&mut self) {
73        unsafe {
74            let resp = &*self.0;
75            psp_free(resp.data_ptr as *const u8);
76        }
77    }
78}
79
80#[repr(transparent)]
81pub struct ResponseBatch(*const CppResponseBatch);
82
83impl ResponseBatch {
84    pub fn size(&self) -> usize {
85        let batch = unsafe { &*self.0 };
86        batch.length as usize
87    }
88
89    pub fn iter_responses(&self) -> impl Iterator<Item = Response> + Send + Sync {
90        let batch = unsafe { &*self.0 };
91        let num_responses = batch.length;
92        (0..num_responses).map(move |idx| {
93            let entries_ptr = batch.entries_ptr as *const CppResponse;
94            Response(unsafe { entries_ptr.offset(idx as isize) })
95        })
96    }
97}
98
99impl Drop for ResponseBatch {
100    fn drop(&mut self) {
101        unsafe {
102            let batch = &*self.0;
103            psp_free(batch.entries_ptr as *const u8);
104            psp_free(self.0 as *const u8)
105        }
106    }
107}
108
109pub struct Request(*const u8, usize);
110
111impl From<&[u8]> for Request {
112    fn from(value: &[u8]) -> Self {
113        let len = value.len();
114        let ptr = unsafe { psp_alloc(len) };
115        unsafe { std::ptr::copy(std::ptr::addr_of!(value[0]), ptr, len) };
116        Request(ptr, len)
117    }
118}
119
120impl Drop for Request {
121    fn drop(&mut self) {
122        unsafe {
123            psp_free(self.0);
124        };
125    }
126}
127
128pub struct Server(*const u8);
129
130impl Server {
131    pub fn new(realtime_mode: bool) -> Self {
132        Server(unsafe { psp_new_server(realtime_mode) })
133    }
134
135    pub fn new_session(&self) -> u32 {
136        unsafe { psp_new_session(self.0) }
137    }
138
139    pub fn handle_request(&self, client_id: u32, request: &Request) -> ResponseBatch {
140        unsafe { psp_handle_request(self.0, client_id, request.0, request.1) }
141    }
142
143    pub fn poll(&self) -> ResponseBatch {
144        unsafe { psp_poll(self.0) }
145    }
146
147    pub fn close_session(&self, session_id: u32) {
148        unsafe { psp_close_session(self.0, session_id) }
149    }
150}
151
152impl Drop for Server {
153    fn drop(&mut self) {
154        unsafe { psp_delete_server(self.0) }
155    }
156}
157
158unsafe impl Send for Server {}
159unsafe impl Sync for Server {}
160
161unsafe impl Send for Request {}
162unsafe impl Sync for Request {}
163
164unsafe impl Send for ResponseBatch {}
165unsafe impl Sync for ResponseBatch {}
166
167unsafe impl Send for Response {}
168unsafe impl Sync for Response {}