1#![no_std]
8#![allow(non_camel_case_types)]
9
10#[cfg(feature = "alloc")]
11extern crate alloc;
12
13use core::mem::MaybeUninit;
14
15use coap_message::{
16 error::RenderableOnMinimal, MessageOption as _, MinimalWritableMessage, MutableWritableMessage,
17 ReadableMessage,
18};
19
20#[allow(non_camel_case_types)]
22pub enum c_void {}
23
24struct Message<'a> {
25 data: MessageVariant<'a>,
26 payload_length: Option<usize>,
37}
38
39enum MessageVariant<'a> {
40 #[cfg(feature = "alloc")]
41 Heap(coap_message_implementations::heap::HeapMessage),
42 InMemory(&'a mut coap_message_implementations::inmemory_write::Message<'a>),
43 }
46
47impl<'a> Message<'a> {
48 unsafe fn from_ptr(ptr: oscore_msg_native_t) -> &'a mut Self {
49 unsafe { &mut *(ptr.0 as *mut Message<'a>) }
50 }
51}
52
53impl<'a> ReadableMessage for Message<'a> {
54 type Code = u8;
55 type MessageOption<'b> = MessageOption<'b> where Self: 'b;
56 type OptionsIter<'b> = OptionsIter<'b> where Self: 'b;
57 fn code(&self) -> u8 {
58 match &self.data {
59 #[cfg(feature = "alloc")]
60 MessageVariant::Heap(m) => m.code(),
61 MessageVariant::InMemory(m) => m.code(),
62 }
63 }
64 fn payload(&self) -> &[u8] {
65 panic!("This function is not used by the oscore_msg_native implementation");
67 }
68 fn options(&self) -> Self::OptionsIter<'_> {
69 match &self.data {
70 #[cfg(feature = "alloc")]
71 MessageVariant::Heap(m) => OptionsIter::Heap(m.options()),
72 MessageVariant::InMemory(m) => OptionsIter::InMemory(m.options()),
73 }
74 }
75}
76
77impl<'a> MinimalWritableMessage for Message<'a> {
78 type AddOptionError = oscore_msgerr_native_t;
81 type SetPayloadError = oscore_msgerr_native_t;
82 type UnionError = oscore_msgerr_native_t;
83
84 type Code = u8;
85 type OptionNumber = u16;
86
87 fn set_code(&mut self, code: u8) {
88 match &mut self.data {
89 #[cfg(feature = "alloc")]
90 MessageVariant::Heap(m) => m.set_code(code),
91 MessageVariant::InMemory(m) => m.set_code(code),
92 }
93 }
94 fn add_option(&mut self, option: u16, data: &[u8]) -> Result<(), oscore_msgerr_native_t> {
95 match &mut self.data {
96 #[cfg(feature = "alloc")]
97 MessageVariant::Heap(m) => map_internal_error(m.add_option(option, data)),
98 MessageVariant::InMemory(m) => map_internal_error(m.add_option(option, data)),
99 }
100 }
101 fn set_payload(&mut self, _: &[u8]) -> Result<(), oscore_msgerr_native_t> {
102 panic!("This function is not used by the oscore_msg_native implementation");
104 }
105}
106
107impl<'a> MutableWritableMessage for Message<'a> {
108 fn available_space(&self) -> usize {
109 match &self.data {
110 #[cfg(feature = "alloc")]
111 MessageVariant::Heap(m) => m.available_space(),
112 MessageVariant::InMemory(m) => m.available_space(),
113 }
114 }
115 fn payload_mut_with_len(&mut self, len: usize) -> Result<&mut [u8], oscore_msgerr_native_t> {
116 match &mut self.data {
117 #[cfg(feature = "alloc")]
118 MessageVariant::Heap(m) => map_internal_error(m.payload_mut_with_len(len)),
119 MessageVariant::InMemory(m) => map_internal_error(m.payload_mut_with_len(len)),
120 }
121 }
122 fn truncate(&mut self, len: usize) -> Result<(), oscore_msgerr_native_t> {
123 self.payload_length = Some(len);
124
125 match &mut self.data {
126 #[cfg(feature = "alloc")]
127 MessageVariant::Heap(m) => map_internal_error(m.truncate(len)),
128 MessageVariant::InMemory(m) => map_internal_error(m.truncate(len)),
129 }
130 }
131 fn mutate_options<F: FnMut(u16, &mut [u8])>(&mut self, f: F) {
132 match &mut self.data {
133 #[cfg(feature = "alloc")]
134 MessageVariant::Heap(m) => m.mutate_options(f),
135 MessageVariant::InMemory(m) => m.mutate_options(f),
136 }
137 }
138}
139
140enum OptionsIter<'a> {
141 #[cfg(feature = "alloc")]
142 Heap(<coap_message_implementations::heap::HeapMessage as ReadableMessage>::OptionsIter<'a>),
143 InMemory(<coap_message_implementations::inmemory_write::Message<'a> as ReadableMessage>::OptionsIter<'a>),
144}
145
146impl<'a> core::iter::Iterator for OptionsIter<'a> {
147 type Item = MessageOption<'a>;
148
149 fn next(&mut self) -> Option<MessageOption<'a>> {
150 match self {
151 #[cfg(feature = "alloc")]
152 OptionsIter::Heap(i) => i.next().map(MessageOption::Heap),
153 OptionsIter::InMemory(i) => i.next().map(MessageOption::InMemory),
154 }
155 }
156}
157
158enum MessageOption<'a> {
159 #[cfg(feature = "alloc")]
160 Heap(<coap_message_implementations::heap::HeapMessage as ReadableMessage>::MessageOption<'a>),
161 InMemory(
162 <coap_message_implementations::inmemory_write::Message<'a> as ReadableMessage>::MessageOption<'a>,
163 ),
164}
165
166impl<'a> coap_message::MessageOption for MessageOption<'a> {
167 fn number(&self) -> u16 {
168 match self {
169 #[cfg(feature = "alloc")]
170 MessageOption::Heap(m) => m.number(),
171 MessageOption::InMemory(m) => m.number(),
172 }
173 }
174
175 fn value(&self) -> &[u8] {
176 match self {
177 #[cfg(feature = "alloc")]
178 MessageOption::Heap(m) => m.value(),
179 MessageOption::InMemory(m) => m.value(),
180 }
181 }
182}
183
184#[repr(C)]
200pub struct oscore_msg_native_t(*mut c_void);
201
202#[repr(C)]
203pub struct oscore_msg_native_optiter_t([u64; 12]);
204
205#[derive(Debug, PartialEq)]
212#[repr(u8)]
213pub enum oscore_msgerr_native_t {
214 ResultOk,
215 UpdateOptionWrongLength,
216 UpdateOptionNotFound,
217 InternalMessageError,
222}
223
224fn map_internal_error<T, E>(r: Result<T, E>) -> Result<T, oscore_msgerr_native_t> {
225 r.map_err(|_| oscore_msgerr_native_t::InternalMessageError)
226}
227
228impl RenderableOnMinimal for oscore_msgerr_native_t {
229 type Error<IE: RenderableOnMinimal + core::fmt::Debug> = IE;
230 fn render<M: MinimalWritableMessage>(
231 self,
232 msg: &mut M,
233 ) -> Result<(), Self::Error<M::UnionError>> {
234 use coap_message::Code;
235 msg.set_code(Code::new(coap_numbers::code::INTERNAL_SERVER_ERROR)?);
236 Ok(())
237 }
238}
239
240impl From<core::convert::Infallible> for oscore_msgerr_native_t {
241 fn from(other: core::convert::Infallible) -> Self {
242 match other {}
243 }
244}
245
246#[no_mangle]
247pub extern "C" fn oscore_msg_native_get_code(msg: oscore_msg_native_t) -> u8 {
248 unsafe { Message::from_ptr(msg) }.code()
249}
250
251#[no_mangle]
252pub extern "C" fn oscore_msg_native_set_code(msg: oscore_msg_native_t, code: u8) {
253 unsafe { Message::from_ptr(msg) }.set_code(code)
254}
255
256#[no_mangle]
257pub extern "C" fn oscore_msg_native_append_option(
258 msg: oscore_msg_native_t,
259 option_number: u16,
260 value: *const u8,
261 value_len: usize,
262) -> oscore_msgerr_native_t {
263 let value = unsafe { core::slice::from_raw_parts(value, value_len) };
264 match unsafe { Message::from_ptr(msg) }.add_option(option_number, value) {
265 Ok(()) => oscore_msgerr_native_t::ResultOk,
266 Err(e) => e,
267 }
268}
269
270#[no_mangle]
271pub extern "C" fn oscore_msg_native_update_option(
272 msg: oscore_msg_native_t,
273 option_number: u16,
274 option_occurrence: usize,
275 value: *const u8,
276 value_len: usize,
277) -> oscore_msgerr_native_t {
278 let msg = unsafe { Message::from_ptr(msg) };
279 let value = unsafe { core::slice::from_raw_parts(value, value_len) };
280
281 let mut result = oscore_msgerr_native_t::ResultOk;
282 let mut occurrence = Some(option_occurrence);
283 msg.mutate_options(|onum, oval| {
284 if onum == option_number {
285 occurrence = match occurrence {
286 Some(0) => {
287 if oval.len() == value.len() {
288 oval[..].copy_from_slice(value);
289 } else {
290 result = oscore_msgerr_native_t::UpdateOptionWrongLength;
291 }
292 None
293 }
294 Some(i) => Some(i - 1),
295 None => None,
296 }
297 }
298 });
299 if occurrence.is_some() {
300 result = oscore_msgerr_native_t::UpdateOptionNotFound;
301 }
302 result
303}
304
305#[no_mangle]
306pub extern "C" fn oscore_msg_native_optiter_init(
307 msg: oscore_msg_native_t,
308 iter: &mut MaybeUninit<oscore_msg_native_optiter_t>,
309) {
310 let msg = unsafe { Message::from_ptr(msg) };
311 assert!(
312 core::mem::size_of::<oscore_msg_native_optiter_t>()
313 >= core::mem::size_of::<OptionsIter<'static>>(),
314 "OptionsIter doesn't fit in oscore_msg_native_optiter_t"
315 );
316 assert!(
317 core::mem::align_of::<oscore_msg_native_optiter_t>()
318 >= core::mem::align_of::<OptionsIter<'static>>(),
319 "oscore_msg_native_optiter_t is insufficiently aligned for OptionsIter"
320 );
321 let iter: &mut MaybeUninit<OptionsIter> = unsafe { core::mem::transmute(iter) };
322 iter.write(msg.options());
323}
324
325#[no_mangle]
326pub extern "C" fn oscore_msg_native_map_payload(
327 msg: oscore_msg_native_t,
328 payload: &mut *mut u8,
329 payload_len: &mut usize,
330) -> oscore_msgerr_native_t {
331 let msg = unsafe { Message::from_ptr(msg) };
332 if let Some(len) = msg.payload_length {
333 *payload_len = len;
334 } else {
335 let original_space = msg.available_space();
336 let available_space = original_space.clamp(0, 4097);
339 *payload_len = available_space.saturating_sub(1);
340 }
341 match msg.payload_mut_with_len(*payload_len) {
342 Ok(result) => {
343 *payload = result.as_mut_ptr();
344 oscore_msgerr_native_t::ResultOk
345 }
346 Err(e) => e,
347 }
348}
349
350#[no_mangle]
351pub extern "C" fn oscore_msgerr_native_is_error(msgerr: oscore_msgerr_native_t) -> bool {
352 msgerr != oscore_msgerr_native_t::ResultOk
353}
354
355#[no_mangle]
356pub extern "C" fn oscore_msg_native_trim_payload(
357 msg: oscore_msg_native_t,
358 payload_len: usize,
359) -> oscore_msgerr_native_t {
360 match unsafe { Message::from_ptr(msg) }.truncate(payload_len) {
361 Ok(()) => oscore_msgerr_native_t::ResultOk,
362 Err(e) => e,
363 }
364}
365
366#[no_mangle]
367pub extern "C" fn oscore_msg_native_optiter_next(
368 _: oscore_msg_native_t,
369 iter: &mut oscore_msg_native_optiter_t,
370 option_number: &mut u16,
371 value: &mut *const u8,
372 value_len: &mut usize,
373) -> bool {
374 let iter: &mut OptionsIter = unsafe { core::mem::transmute(iter) };
375 if let Some(o) = iter.next() {
376 *option_number = o.number();
377 let value_slice = o.value();
378 *value = value_slice.as_ptr();
379 *value_len = value_slice.len();
380 true
381 } else {
382 false
383 }
384}
385
386#[no_mangle]
387pub extern "C" fn oscore_msg_native_optiter_finish(
388 _: oscore_msg_native_t,
389 iter: &mut MaybeUninit<oscore_msg_native_optiter_t>,
390) -> oscore_msgerr_native_t {
391 let iter: &mut MaybeUninit<OptionsIter> = unsafe { core::mem::transmute(iter) };
392 unsafe { iter.assume_init_drop() };
393 oscore_msgerr_native_t::ResultOk
397}
398
399#[cfg(feature = "alloc")]
400#[no_mangle]
401pub extern "C" fn oscore_test_msg_create() -> oscore_msg_native_t {
402 let msg = alloc::boxed::Box::new(Message {
403 data: MessageVariant::Heap(coap_message_implementations::heap::HeapMessage::new()),
404 payload_length: None,
405 });
406
407 oscore_msg_native_t(alloc::boxed::Box::into_raw(msg) as *mut _)
408}
409
410#[cfg(feature = "alloc")]
411#[no_mangle]
412pub extern "C" fn oscore_test_msg_destroy(msg: oscore_msg_native_t) {
413 let boxed = unsafe { alloc::boxed::Box::from_raw(msg.0) };
414 drop(boxed);
415}
416
417#[cfg(feature = "alloc")]
423pub fn with_heapmessage_as_msg_native<F, R>(
426 msg: coap_message_implementations::heap::HeapMessage,
427 f: F,
428) -> R
429where
430 F: FnOnce(oscore_msg_native_t) -> R,
431{
432 let payload_len = msg.payload().len();
434 let mut wrapped_message = Message {
435 data: MessageVariant::Heap(msg),
436 payload_length: Some(payload_len),
437 };
438 f(oscore_msg_native_t(
439 &mut wrapped_message as *mut _ as *mut _,
440 ))
441}
442
443pub fn with_inmemory_as_msg_native<'a, 'b: 'a, F, R>(
447 msg: &'a mut coap_message_implementations::inmemory_write::Message<'b>,
448 f: F,
449) -> R
450where
451 F: FnOnce(oscore_msg_native_t) -> R,
452{
453 let msg: &'a mut coap_message_implementations::inmemory_write::Message<'a> =
457 unsafe { core::mem::transmute(msg) };
458
459 let read_payload_len = msg.payload().len();
467 let mut wrapped_message = Message {
468 data: MessageVariant::InMemory(msg),
469 payload_length: if read_payload_len == 0 {
470 None
473 } else {
474 Some(read_payload_len)
475 },
476 };
477 f(oscore_msg_native_t(
478 &mut wrapped_message as *mut _ as *mut _,
479 ))
480}
481
482pub trait WithMsgNative: sealed::Sealed {
484 fn with_msg_native<F: FnOnce(oscore_msg_native_t) -> R, R>(self, f: F) -> R;
485}
486
487impl<'a, 'b> WithMsgNative for &'a mut coap_message_implementations::inmemory_write::Message<'b> {
488 fn with_msg_native<F: FnOnce(oscore_msg_native_t) -> R, R>(self, f: F) -> R {
489 with_inmemory_as_msg_native(self, f)
490 }
491}
492#[cfg(feature = "alloc")]
493impl WithMsgNative for coap_message_implementations::heap::HeapMessage {
494 fn with_msg_native<F: FnOnce(oscore_msg_native_t) -> R, R>(self, f: F) -> R {
495 with_heapmessage_as_msg_native(self, f)
496 }
497}
498
499mod sealed {
500 pub trait Sealed {}
501
502 impl<'a, 'b> Sealed for &'a mut coap_message_implementations::inmemory_write::Message<'b> {}
503 #[cfg(feature = "alloc")]
504 impl Sealed for coap_message_implementations::heap::HeapMessage {}
505}