1use core::mem::{align_of, size_of};
4use core::ptr;
5
6#[cfg(feature = "std")]
7use std::boxed::Box;
8
9use msrt::endpoint::{ClientEndpoint, EngineConfig, PassiveEndpoint};
10
11use crate::config::MsrtConfig;
12use crate::constants::{
13 ENDPOINT_STORAGE_BYTES, MAX_EVENT_BYTES, MSRT_ROLE_CLIENT, MSRT_ROLE_PASSIVE,
14 MSRT_STATUS_INVALID_STORAGE, MSRT_STATUS_NULL, MSRT_STATUS_OK, MSRT_STATUS_UNSUPPORTED,
15};
16
17#[repr(C, align(8))]
22#[derive(Clone, Copy)]
23pub struct MsrtEndpointStorage {
24 pub(crate) bytes: [u8; ENDPOINT_STORAGE_BYTES],
25}
26
27pub struct MsrtEndpoint {
29 pub(crate) inner: EndpointInner,
30 pub(crate) tx_buf: [u8; MAX_EVENT_BYTES],
31}
32
33pub(crate) enum EndpointInner {
34 Client(ClientEndpoint),
35 Passive(PassiveEndpoint),
36}
37
38impl EndpointInner {
39 pub(crate) fn new(role: u32, config: EngineConfig) -> Result<Self, ()> {
40 match role {
41 MSRT_ROLE_CLIENT => Ok(Self::Client(ClientEndpoint::new(config))),
42 MSRT_ROLE_PASSIVE => Ok(Self::Passive(PassiveEndpoint::new(config))),
43 _ => Err(()),
44 }
45 }
46}
47
48pub const fn endpoint_storage_size() -> usize {
50 size_of::<MsrtEndpoint>()
51}
52
53pub const fn endpoint_storage_align() -> usize {
55 align_of::<MsrtEndpoint>()
56}
57
58pub(crate) unsafe fn init_endpoint(
60 storage: *mut MsrtEndpointStorage,
61 config: *const MsrtConfig,
62 out: *mut *mut MsrtEndpoint,
63) -> i32 {
64 let Some(storage) = (unsafe { storage.as_mut() }) else {
65 return MSRT_STATUS_NULL;
66 };
67 let Some(out) = (unsafe { out.as_mut() }) else {
68 return MSRT_STATUS_NULL;
69 };
70
71 *out = ptr::null_mut();
72 if endpoint_storage_size() > ENDPOINT_STORAGE_BYTES
73 || endpoint_storage_align() > align_of::<MsrtEndpointStorage>()
74 {
75 return MSRT_STATUS_INVALID_STORAGE;
76 }
77
78 let config = if config.is_null() {
79 MsrtConfig::default()
80 } else {
81 unsafe { *config }
82 };
83
84 let Ok(engine_config) = config.engine_config() else {
85 return MSRT_STATUS_UNSUPPORTED;
86 };
87 let Ok(inner) = EndpointInner::new(config.role, engine_config) else {
88 return MSRT_STATUS_UNSUPPORTED;
89 };
90
91 let endpoint = ptr::from_mut(storage).cast::<MsrtEndpoint>();
92 unsafe {
93 endpoint.write(MsrtEndpoint {
94 inner,
95 tx_buf: [0; MAX_EVENT_BYTES],
96 });
97 }
98 *out = endpoint;
99 MSRT_STATUS_OK
100}
101
102pub(crate) unsafe fn deinit_endpoint(endpoint: *mut MsrtEndpoint) -> i32 {
104 if endpoint.is_null() {
105 return MSRT_STATUS_NULL;
106 }
107
108 unsafe {
109 ptr::drop_in_place(endpoint);
110 }
111 MSRT_STATUS_OK
112}
113
114#[cfg(feature = "std")]
116pub(crate) unsafe fn new_endpoint(config: *const MsrtConfig) -> *mut MsrtEndpoint {
117 let mut storage = MsrtEndpointStorage {
118 bytes: [0; ENDPOINT_STORAGE_BYTES],
119 };
120 let mut endpoint = ptr::null_mut();
121 let status = unsafe { init_endpoint(&mut storage, config, &mut endpoint) };
122 if status != MSRT_STATUS_OK {
123 return ptr::null_mut();
124 }
125
126 Box::into_raw(Box::new(unsafe { ptr::read(endpoint) }))
127}
128
129#[cfg(feature = "std")]
131pub(crate) unsafe fn free_endpoint(endpoint: *mut MsrtEndpoint) {
132 if endpoint.is_null() {
133 return;
134 }
135
136 drop(unsafe { Box::from_raw(endpoint) });
137}
138
139#[cfg(test)]
140pub(crate) fn endpoint_from_storage(
141 config: *const MsrtConfig,
142) -> (*mut MsrtEndpointStorage, *mut MsrtEndpoint) {
143 let storage = Box::into_raw(Box::new(MsrtEndpointStorage {
144 bytes: [0; ENDPOINT_STORAGE_BYTES],
145 }));
146 let mut endpoint = ptr::null_mut();
147 assert_eq!(
148 unsafe { init_endpoint(storage, config, &mut endpoint) },
149 MSRT_STATUS_OK
150 );
151 (storage, endpoint)
152}
153
154#[cfg(test)]
155pub(crate) unsafe fn free_storage_endpoint(
156 storage: *mut MsrtEndpointStorage,
157 endpoint: *mut MsrtEndpoint,
158) {
159 assert_eq!(unsafe { deinit_endpoint(endpoint) }, MSRT_STATUS_OK);
160 drop(unsafe { Box::from_raw(storage) });
161}