1#![no_std]
8#![allow(non_camel_case_types)]
9#![allow(
10 async_fn_in_trait,
11 reason = "our functions should all inherit their Send-ness from their callbacks"
12)]
13
14#[cfg(feature = "alloc")]
15extern crate alloc;
16
17use core::future::Future;
18use core::mem::MaybeUninit;
19
20use coap_message::{
21 error::RenderableOnMinimal, MessageOption as _, MinimalWritableMessage, MutableWritableMessage,
22 ReadableMessage,
23};
24
25#[allow(non_camel_case_types)]
27pub enum c_void {}
28
29struct Message<'a> {
30 data: MessageVariant<'a>,
31 payload_length: Option<usize>,
42}
43
44enum MessageVariant<'a> {
45 #[cfg(feature = "alloc")]
46 Heap(coap_message_implementations::heap::HeapMessage),
47 InMemory(&'a mut coap_message_implementations::inmemory_write::Message<'a>),
48 }
51
52impl<'a> Message<'a> {
53 unsafe fn from_ptr(ptr: oscore_msg_native_t) -> &'a mut Self {
54 unsafe { &mut *(ptr.0 as *mut Message<'a>) }
55 }
56}
57
58impl<'a> ReadableMessage for Message<'a> {
59 type Code = u8;
60 type MessageOption<'b>
61 = MessageOption<'b>
62 where
63 Self: 'b;
64 type OptionsIter<'b>
65 = OptionsIter<'b>
66 where
67 Self: 'b;
68 fn code(&self) -> u8 {
69 match &self.data {
70 #[cfg(feature = "alloc")]
71 MessageVariant::Heap(m) => m.code(),
72 MessageVariant::InMemory(m) => m.code(),
73 }
74 }
75 fn payload(&self) -> &[u8] {
76 panic!("This function is not used by the oscore_msg_native implementation");
78 }
79 fn options(&self) -> Self::OptionsIter<'_> {
80 match &self.data {
81 #[cfg(feature = "alloc")]
82 MessageVariant::Heap(m) => OptionsIter::Heap(m.options()),
83 MessageVariant::InMemory(m) => OptionsIter::InMemory(m.options()),
84 }
85 }
86}
87
88impl<'a> MinimalWritableMessage for Message<'a> {
89 type AddOptionError = oscore_msgerr_native_t;
92 type SetPayloadError = oscore_msgerr_native_t;
93 type UnionError = oscore_msgerr_native_t;
94
95 type Code = u8;
96 type OptionNumber = u16;
97
98 fn set_code(&mut self, code: u8) {
99 match &mut self.data {
100 #[cfg(feature = "alloc")]
101 MessageVariant::Heap(m) => m.set_code(code),
102 MessageVariant::InMemory(m) => m.set_code(code),
103 }
104 }
105 fn add_option(&mut self, option: u16, data: &[u8]) -> Result<(), oscore_msgerr_native_t> {
106 match &mut self.data {
107 #[cfg(feature = "alloc")]
108 MessageVariant::Heap(m) => map_internal_error(m.add_option(option, data)),
109 MessageVariant::InMemory(m) => map_internal_error(m.add_option(option, data)),
110 }
111 }
112 fn set_payload(&mut self, _: &[u8]) -> Result<(), oscore_msgerr_native_t> {
113 panic!("This function is not used by the oscore_msg_native implementation");
115 }
116}
117
118impl<'a> MutableWritableMessage for Message<'a> {
119 fn available_space(&self) -> usize {
120 match &self.data {
121 #[cfg(feature = "alloc")]
122 MessageVariant::Heap(m) => m.available_space(),
123 MessageVariant::InMemory(m) => m.available_space(),
124 }
125 }
126 fn payload_mut_with_len(&mut self, len: usize) -> Result<&mut [u8], oscore_msgerr_native_t> {
127 match &mut self.data {
128 #[cfg(feature = "alloc")]
129 MessageVariant::Heap(m) => map_internal_error(m.payload_mut_with_len(len)),
130 MessageVariant::InMemory(m) => map_internal_error(m.payload_mut_with_len(len)),
131 }
132 }
133 fn truncate(&mut self, len: usize) -> Result<(), oscore_msgerr_native_t> {
134 self.payload_length = Some(len);
135
136 match &mut self.data {
137 #[cfg(feature = "alloc")]
138 MessageVariant::Heap(m) => map_internal_error(m.truncate(len)),
139 MessageVariant::InMemory(m) => map_internal_error(m.truncate(len)),
140 }
141 }
142 fn mutate_options<F: FnMut(u16, &mut [u8])>(&mut self, f: F) {
143 match &mut self.data {
144 #[cfg(feature = "alloc")]
145 MessageVariant::Heap(m) => m.mutate_options(f),
146 MessageVariant::InMemory(m) => m.mutate_options(f),
147 }
148 }
149}
150
151enum OptionsIter<'a> {
152 #[cfg(feature = "alloc")]
153 Heap(<coap_message_implementations::heap::HeapMessage as ReadableMessage>::OptionsIter<'a>),
154 InMemory(<coap_message_implementations::inmemory_write::Message<'a> as ReadableMessage>::OptionsIter<'a>),
155}
156
157impl<'a> core::iter::Iterator for OptionsIter<'a> {
158 type Item = MessageOption<'a>;
159
160 fn next(&mut self) -> Option<MessageOption<'a>> {
161 match self {
162 #[cfg(feature = "alloc")]
163 OptionsIter::Heap(i) => i.next().map(MessageOption::Heap),
164 OptionsIter::InMemory(i) => i.next().map(MessageOption::InMemory),
165 }
166 }
167}
168
169enum MessageOption<'a> {
170 #[cfg(feature = "alloc")]
171 Heap(<coap_message_implementations::heap::HeapMessage as ReadableMessage>::MessageOption<'a>),
172 InMemory(
173 <coap_message_implementations::inmemory_write::Message<'a> as ReadableMessage>::MessageOption<'a>,
174 ),
175}
176
177impl<'a> coap_message::MessageOption for MessageOption<'a> {
178 fn number(&self) -> u16 {
179 match self {
180 #[cfg(feature = "alloc")]
181 MessageOption::Heap(m) => m.number(),
182 MessageOption::InMemory(m) => m.number(),
183 }
184 }
185
186 fn value(&self) -> &[u8] {
187 match self {
188 #[cfg(feature = "alloc")]
189 MessageOption::Heap(m) => m.value(),
190 MessageOption::InMemory(m) => m.value(),
191 }
192 }
193}
194
195#[repr(C)]
211pub struct oscore_msg_native_t(*mut c_void);
212
213#[repr(C)]
214pub struct oscore_msg_native_optiter_t([u64; 12]);
215
216#[derive(Debug, PartialEq)]
223#[repr(u8)]
224pub enum oscore_msgerr_native_t {
225 ResultOk,
226 UpdateOptionWrongLength,
227 UpdateOptionNotFound,
228 InternalMessageError,
233}
234
235fn map_internal_error<T, E>(r: Result<T, E>) -> Result<T, oscore_msgerr_native_t> {
236 r.map_err(|_| oscore_msgerr_native_t::InternalMessageError)
237}
238
239impl RenderableOnMinimal for oscore_msgerr_native_t {
240 type Error<IE: RenderableOnMinimal + core::fmt::Debug> = IE;
241 fn render<M: MinimalWritableMessage>(
242 self,
243 msg: &mut M,
244 ) -> Result<(), Self::Error<M::UnionError>> {
245 use coap_message::Code;
246 msg.set_code(Code::new(coap_numbers::code::INTERNAL_SERVER_ERROR)?);
247 Ok(())
248 }
249}
250
251impl From<core::convert::Infallible> for oscore_msgerr_native_t {
252 fn from(other: core::convert::Infallible) -> Self {
253 match other {}
254 }
255}
256
257#[no_mangle]
258pub unsafe extern "C" fn oscore_msg_native_get_code(msg: oscore_msg_native_t) -> u8 {
259 unsafe { Message::from_ptr(msg) }.code()
260}
261
262#[no_mangle]
263pub unsafe extern "C" fn oscore_msg_native_set_code(msg: oscore_msg_native_t, code: u8) {
264 unsafe { Message::from_ptr(msg) }.set_code(code)
265}
266
267#[no_mangle]
268pub unsafe extern "C" fn oscore_msg_native_append_option(
269 msg: oscore_msg_native_t,
270 option_number: u16,
271 value: *const u8,
272 value_len: usize,
273) -> oscore_msgerr_native_t {
274 let value = unsafe { core::slice::from_raw_parts(value, value_len) };
275 match unsafe { Message::from_ptr(msg) }.add_option(option_number, value) {
276 Ok(()) => oscore_msgerr_native_t::ResultOk,
277 Err(e) => e,
278 }
279}
280
281#[no_mangle]
282pub unsafe extern "C" fn oscore_msg_native_update_option(
283 msg: oscore_msg_native_t,
284 option_number: u16,
285 option_occurrence: usize,
286 value: *const u8,
287 value_len: usize,
288) -> oscore_msgerr_native_t {
289 let msg = unsafe { Message::from_ptr(msg) };
290 let value = unsafe { core::slice::from_raw_parts(value, value_len) };
291
292 let mut result = oscore_msgerr_native_t::ResultOk;
293 let mut occurrence = Some(option_occurrence);
294 msg.mutate_options(|onum, oval| {
295 if onum == option_number {
296 occurrence = match occurrence {
297 Some(0) => {
298 if oval.len() == value.len() {
299 oval[..].copy_from_slice(value);
300 } else {
301 result = oscore_msgerr_native_t::UpdateOptionWrongLength;
302 }
303 None
304 }
305 Some(i) => Some(i - 1),
306 None => None,
307 }
308 }
309 });
310 if occurrence.is_some() {
311 result = oscore_msgerr_native_t::UpdateOptionNotFound;
312 }
313 result
314}
315
316#[no_mangle]
317pub unsafe extern "C" fn oscore_msg_native_optiter_init(
318 msg: oscore_msg_native_t,
319 iter: &mut MaybeUninit<oscore_msg_native_optiter_t>,
320) {
321 let msg = unsafe { Message::from_ptr(msg) };
322 assert!(
323 core::mem::size_of::<oscore_msg_native_optiter_t>()
324 >= core::mem::size_of::<OptionsIter<'static>>(),
325 "OptionsIter doesn't fit in oscore_msg_native_optiter_t"
326 );
327 assert!(
328 core::mem::align_of::<oscore_msg_native_optiter_t>()
329 >= core::mem::align_of::<OptionsIter<'static>>(),
330 "oscore_msg_native_optiter_t is insufficiently aligned for OptionsIter"
331 );
332 let iter: &mut MaybeUninit<OptionsIter> = unsafe { core::mem::transmute(iter) };
333 iter.write(msg.options());
334}
335
336#[no_mangle]
337pub unsafe extern "C" fn oscore_msg_native_map_payload(
338 msg: oscore_msg_native_t,
339 payload: &mut *mut u8,
340 payload_len: &mut usize,
341) -> oscore_msgerr_native_t {
342 let msg = unsafe { Message::from_ptr(msg) };
343 if let Some(len) = msg.payload_length {
344 *payload_len = len;
345 } else {
346 let original_space = msg.available_space();
347 let available_space = original_space.clamp(0, 4097);
350 *payload_len = available_space.saturating_sub(1);
351 }
352 match msg.payload_mut_with_len(*payload_len) {
353 Ok(result) => {
354 *payload = result.as_mut_ptr();
355 oscore_msgerr_native_t::ResultOk
356 }
357 Err(e) => e,
358 }
359}
360
361#[no_mangle]
362pub unsafe extern "C" fn oscore_msgerr_native_is_error(msgerr: oscore_msgerr_native_t) -> bool {
363 msgerr != oscore_msgerr_native_t::ResultOk
364}
365
366#[no_mangle]
367pub unsafe extern "C" fn oscore_msg_native_trim_payload(
368 msg: oscore_msg_native_t,
369 payload_len: usize,
370) -> oscore_msgerr_native_t {
371 match unsafe { Message::from_ptr(msg) }.truncate(payload_len) {
372 Ok(()) => oscore_msgerr_native_t::ResultOk,
373 Err(e) => e,
374 }
375}
376
377#[no_mangle]
378pub unsafe extern "C" fn oscore_msg_native_optiter_next(
379 _: oscore_msg_native_t,
380 iter: &mut oscore_msg_native_optiter_t,
381 option_number: &mut u16,
382 value: &mut *const u8,
383 value_len: &mut usize,
384) -> bool {
385 let iter: &mut OptionsIter = unsafe { core::mem::transmute(iter) };
386 if let Some(o) = iter.next() {
387 *option_number = o.number();
388 let value_slice = o.value();
389 *value = value_slice.as_ptr();
390 *value_len = value_slice.len();
391 true
392 } else {
393 false
394 }
395}
396
397#[no_mangle]
398pub unsafe extern "C" fn oscore_msg_native_optiter_finish(
399 _: oscore_msg_native_t,
400 iter: &mut MaybeUninit<oscore_msg_native_optiter_t>,
401) -> oscore_msgerr_native_t {
402 let iter: &mut MaybeUninit<OptionsIter> = unsafe { core::mem::transmute(iter) };
403 unsafe { iter.assume_init_drop() };
404 oscore_msgerr_native_t::ResultOk
408}
409
410#[cfg(feature = "alloc")]
411#[no_mangle]
412pub unsafe extern "C" fn oscore_test_msg_create() -> oscore_msg_native_t {
413 let msg = alloc::boxed::Box::new(Message {
414 data: MessageVariant::Heap(coap_message_implementations::heap::HeapMessage::new()),
415 payload_length: None,
416 });
417
418 oscore_msg_native_t(alloc::boxed::Box::into_raw(msg) as *mut _)
419}
420
421#[cfg(feature = "alloc")]
422#[no_mangle]
423pub unsafe extern "C" fn oscore_test_msg_destroy(msg: oscore_msg_native_t) {
424 let boxed = unsafe { alloc::boxed::Box::from_raw(msg.0) };
425 drop(boxed);
426}
427
428#[cfg(feature = "alloc")]
437async fn async_with_heapmessage_as_msg_native<F, R>(
440 msg: coap_message_implementations::heap::HeapMessage,
441 f: F,
442) -> R
443where
444 F: AsyncFnOnce(oscore_msg_native_t) -> R,
445{
446 let payload_len = msg.payload().len();
448 let mut wrapped_message = Message {
449 data: MessageVariant::Heap(msg),
450 payload_length: Some(payload_len),
451 };
452 f(oscore_msg_native_t(
453 &mut wrapped_message as *mut _ as *mut _,
454 ))
455 .await
456}
457
458#[cfg(feature = "alloc")]
466pub fn with_heapmessage_as_msg_native<F, R>(
467 msg: coap_message_implementations::heap::HeapMessage,
468 f: F,
469) -> R
470where
471 F: FnOnce(oscore_msg_native_t) -> R,
472{
473 msg.with_msg_native(f)
474}
475
476async fn async_with_inmemory_as_msg_native<'a, 'b: 'a, F, R>(
483 msg: &'a mut coap_message_implementations::inmemory_write::Message<'b>,
484 f: F,
485) -> R
486where
487 F: AsyncFnOnce(oscore_msg_native_t) -> R,
488{
489 let msg: &'a mut coap_message_implementations::inmemory_write::Message<'a> =
493 unsafe { core::mem::transmute(msg) };
494
495 let read_payload_len = msg.payload().len();
503 let mut wrapped_message = Message {
504 data: MessageVariant::InMemory(msg),
505 payload_length: if read_payload_len == 0 {
506 None
509 } else {
510 Some(read_payload_len)
511 },
512 };
513 f(oscore_msg_native_t(
514 &mut wrapped_message as *mut _ as *mut _,
515 ))
516 .await
517}
518
519pub fn with_inmemory_as_msg_native<'a, 'b: 'a, F, R>(
527 msg: &'a mut coap_message_implementations::inmemory_write::Message<'b>,
528 f: F,
529) -> R
530where
531 F: FnOnce(oscore_msg_native_t) -> R,
532{
533 msg.with_msg_native(f)
534}
535
536pub trait WithMsgNative: sealed::Sealed {
538 fn with_msg_native<F: FnOnce(oscore_msg_native_t) -> R, R>(self, f: F) -> R
539 where
540 Self: Sized,
541 {
542 let future = self.async_with_msg_native(async |m| f(m));
543 let future = core::pin::pin!(future);
544 let mut context = core::task::Context::from_waker(core::task::Waker::noop());
545 match future.poll(&mut context) {
546 core::task::Poll::Ready(r) => r,
547 core::task::Poll::Pending => unreachable!("async_with_inmemory_as_msg_native's only await point is in the callback, and the provided callback has none"),
548 }
549 }
550
551 async fn async_with_msg_native<F: AsyncFnOnce(oscore_msg_native_t) -> R, R>(self, f: F) -> R;
552}
553
554impl<'a, 'b> WithMsgNative for &'a mut coap_message_implementations::inmemory_write::Message<'b> {
555 async fn async_with_msg_native<F: AsyncFnOnce(oscore_msg_native_t) -> R, R>(self, f: F) -> R {
556 async_with_inmemory_as_msg_native(self, f).await
557 }
558}
559#[cfg(feature = "alloc")]
560impl WithMsgNative for coap_message_implementations::heap::HeapMessage {
561 async fn async_with_msg_native<F: AsyncFnOnce(oscore_msg_native_t) -> R, R>(self, f: F) -> R {
562 async_with_heapmessage_as_msg_native(self, f).await
563 }
564}
565
566mod sealed {
567 pub trait Sealed {}
568
569 impl<'a, 'b> Sealed for &'a mut coap_message_implementations::inmemory_write::Message<'b> {}
570 #[cfg(feature = "alloc")]
571 impl Sealed for coap_message_implementations::heap::HeapMessage {}
572}