1use crate::prelude_internal::*;
8use num_derive::FromPrimitive;
9
10#[derive(Debug, Copy, Clone, Eq, Ord, PartialOrd, PartialEq, FromPrimitive)]
13pub enum Priority {
14 Low = OT_MESSAGE_PRIORITY_LOW as isize,
17
18 Normal = OT_MESSAGE_PRIORITY_NORMAL as isize,
23
24 High = OT_MESSAGE_PRIORITY_HIGH as isize,
27}
28
29impl Default for Priority {
30 fn default() -> Self {
32 Priority::Normal
33 }
34}
35
36impl Priority {
37 pub fn as_ot_message_priority(self) -> otMessagePriority {
39 self as otMessagePriority
40 }
41}
42
43impl From<otMessagePriority> for Priority {
44 fn from(x: otMessagePriority) -> Self {
45 use num_traits::FromPrimitive;
46 Self::from_u32(x).unwrap_or_else(|| panic!("Unknown otMessagePriority value: {x}"))
47 }
48}
49
50impl From<Priority> for otMessagePriority {
51 fn from(x: Priority) -> Self {
52 x.as_ot_message_priority()
53 }
54}
55
56impl From<u8> for Priority {
57 fn from(x: u8) -> Self {
58 use num_traits::FromPrimitive;
59 Self::from_u8(x).unwrap_or_else(|| panic!("Unknown otMessagePriority value: {x}"))
60 }
61}
62
63impl From<Priority> for u8 {
64 #[allow(clippy::unnecessary_fallible_conversions)]
65 fn from(x: Priority) -> Self {
66 x.try_into().unwrap()
67 }
68}
69
70#[derive(Debug, Copy, Clone, Eq, Ord, PartialOrd, PartialEq, FromPrimitive)]
77pub enum Origin {
78 ThreadNetif = OT_MESSAGE_ORIGIN_THREAD_NETIF as isize,
81
82 HostTrusted = OT_MESSAGE_ORIGIN_HOST_TRUSTED as isize,
87
88 HostUntrusted = OT_MESSAGE_ORIGIN_HOST_UNTRUSTED as isize,
92}
93
94impl Origin {
95 pub fn as_ot_message_origin(self) -> otMessageOrigin {
97 self as otMessageOrigin
98 }
99}
100
101impl From<otMessageOrigin> for Origin {
102 fn from(x: otMessageOrigin) -> Self {
103 use num_traits::FromPrimitive;
104 Self::from_u32(x).unwrap_or_else(|| panic!("Unknown otMessageOrigin value: {x}"))
105 }
106}
107
108impl From<Origin> for otMessageOrigin {
109 fn from(x: Origin) -> Self {
110 x.as_ot_message_origin()
111 }
112}
113
114#[derive(Clone)]
117#[repr(transparent)]
118pub struct Info(pub otMessageInfo);
119
120impl_ot_castable!(Info, otMessageInfo);
121
122impl AsRef<Info> for Info {
123 fn as_ref(&self) -> &Info {
124 self
125 }
126}
127
128impl Info {
129 pub fn new(local: SockAddr, remote: SockAddr) -> Info {
131 Info(otMessageInfo {
132 mSockAddr: local.addr().into_ot(),
133 mPeerAddr: remote.addr().into_ot(),
134 mSockPort: local.port(),
135 mPeerPort: remote.port(),
136 ..otMessageInfo::default()
137 })
138 }
139
140 pub fn ecn(&self) -> u8 {
142 self.0.mEcn()
143 }
144
145 pub fn set_ecn(&mut self, ecn: u8) {
147 self.0.set_mEcn(ecn)
148 }
149
150 pub fn hop_limit(&self) -> u8 {
152 self.0.mHopLimit
153 }
154
155 pub fn set_hop_limit(&mut self, hop_limit: u8) {
157 self.0.mHopLimit = hop_limit
158 }
159
160 pub fn is_host_interface(&self) -> bool {
162 self.0.mIsHostInterface()
163 }
164
165 pub fn set_host_interface(&mut self, host_interface: bool) {
167 self.0.set_mIsHostInterface(host_interface)
168 }
169
170 pub fn multicast_loop(&self) -> bool {
172 self.0.mMulticastLoop()
173 }
174
175 pub fn set_multicast_loop(&mut self, multicast_loop: bool) {
177 self.0.set_mMulticastLoop(multicast_loop)
178 }
179
180 pub fn allow_zero_hop_limit(&self) -> bool {
182 self.0.mAllowZeroHopLimit()
183 }
184
185 pub fn set_allow_zero_hop_limit(&mut self, allow_zero_hop_limit: bool) {
187 self.0.set_mAllowZeroHopLimit(allow_zero_hop_limit)
188 }
189
190 pub fn sock_name(&self) -> SockAddr {
192 SockAddr::new(Ip6Address::from_ot(self.0.mSockAddr), self.0.mSockPort)
193 }
194
195 pub fn peer_name(&self) -> SockAddr {
197 SockAddr::new(Ip6Address::from_ot(self.0.mPeerAddr), self.0.mPeerPort)
198 }
199}
200
201impl std::fmt::Debug for Info {
202 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203 f.debug_struct("otMessageInfo")
204 .field("sock_name", &self.sock_name())
205 .field("peer_name", &self.peer_name())
206 .field("ecn", &self.ecn())
207 .field("hop_limit", &self.hop_limit())
208 .field("allow_zero_hop_limit", &self.allow_zero_hop_limit())
209 .field("multicast_loop", &self.multicast_loop())
210 .field("is_host_interface", &self.is_host_interface())
211 .finish()
212 }
213}
214
215#[derive(Debug, Clone)]
218#[repr(transparent)]
219pub struct Settings(pub otMessageSettings);
220
221impl_ot_castable!(Settings, otMessageSettings);
222
223impl AsRef<Settings> for Settings {
224 fn as_ref(&self) -> &Settings {
225 self
226 }
227}
228
229impl Default for Settings {
230 fn default() -> Self {
231 Settings(otMessageSettings {
232 mLinkSecurityEnabled: true,
233 mPriority: OT_MESSAGE_PRIORITY_NORMAL.try_into().unwrap(),
234 })
235 }
236}
237
238impl Settings {
239 pub fn set_priority(mut self, priority: Priority) -> Self {
241 self.0.mPriority = priority.into();
242 self
243 }
244
245 pub fn set_link_security(mut self, enabled: bool) -> Self {
247 self.0.mLinkSecurityEnabled = enabled;
248 self
249 }
250}
251
252#[repr(transparent)]
261pub struct Message<'a>(otMessage, PhantomData<*mut otMessage>, PhantomData<&'a ()>);
262
263impl std::fmt::Debug for Message<'_> {
264 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265 f.debug_struct("otMessage")
266 .field("otPtr", &self.as_ot_ptr())
267 .field("len", &self.len())
268 .field("offset", &self.offset())
269 .field("RSSI", &self.rssi())
270 .finish()
271 }
272}
273
274unsafe impl ot::Boxable for Message<'_> {
277 type OtType = otMessage;
278 unsafe fn finalize(&mut self) {
279 unsafe { otMessageFree(self.as_ot_ptr()) }
280 }
281}
282
283impl<'a> Message<'a> {
284 pub fn ip6_new<T: ot::Boxable<OtType = otInstance>>(
286 instance: &'a T,
287 settings: Option<&Settings>,
288 ) -> Result<ot::Box<Message<'a>>, ot::NoBufs> {
289 unsafe {
290 ot::Box::from_ot_ptr(otIp6NewMessage(
294 instance.as_ot_ptr(),
295 settings.map(|x| x.as_ref().as_ot_ptr()).unwrap_or(null()),
296 ))
297 }
298 .ok_or(ot::NoBufs)
299 }
300
301 pub fn ip6_new_from_bytes<T: ot::Boxable<OtType = otInstance>, D: AsRef<[u8]>>(
308 instance: &'a T,
309 data: D,
310 settings: Option<&Settings>,
311 ) -> Result<ot::Box<Message<'a>>, ot::MalformedOrNoBufs> {
312 let data = data.as_ref();
313 unsafe {
314 ot::Box::from_ot_ptr(otIp6NewMessageFromBuffer(
318 instance.as_ot_ptr(),
319 data.as_ptr(),
320 data.len().try_into().expect("ot::Message::ip6_new_from_bytes: Buffer too large"),
321 settings.map(|x| x.as_ref().as_ot_ptr()).unwrap_or(null()),
322 ))
323 }
324 .ok_or(ot::MalformedOrNoBufs)
325 }
326
327 pub fn ip4_new<T: ot::Boxable<OtType = otInstance>>(
329 instance: &'a T,
330 settings: Option<&Settings>,
331 ) -> Result<ot::Box<Message<'a>>, ot::NoBufs> {
332 unsafe {
333 ot::Box::from_ot_ptr(otIp4NewMessage(
337 instance.as_ot_ptr(),
338 settings.map(|x| x.as_ref().as_ot_ptr()).unwrap_or(null()),
339 ))
340 }
341 .ok_or(ot::NoBufs)
342 }
343}
344
345impl<'a> Message<'a> {
346 pub fn udp_new<T: ot::Boxable<OtType = otInstance>>(
348 instance: &'a T,
349 settings: Option<&Settings>,
350 ) -> Result<ot::Box<Message<'a>>, ot::NoBufs> {
351 unsafe {
352 ot::Box::from_ot_ptr(otUdpNewMessage(
356 instance.as_ot_ptr(),
357 settings.map(|x| x.as_ref().as_ot_ptr()).unwrap_or(null()),
358 ))
359 }
360 .ok_or(ot::NoBufs)
361 }
362}
363
364impl Message<'_> {
365 pub fn append(&mut self, data: &[u8]) -> Result {
370 Error::from(unsafe {
371 otMessageAppend(
374 self.as_ot_ptr(),
375 data.as_ptr() as *const ::std::os::raw::c_void,
376 data.len().try_into().or(Err(Error::InvalidArgs))?,
377 )
378 })
379 .into()
380 }
381
382 pub fn is_link_security_enabled(&self) -> bool {
385 unsafe { otMessageIsLinkSecurityEnabled(self.as_ot_ptr()) }
386 }
387
388 #[allow(clippy::len_without_is_empty)]
390 pub fn len(&self) -> usize {
391 unsafe { otMessageGetLength(self.as_ot_ptr()).into() }
392 }
393
394 pub fn set_len(&mut self, len: usize) -> Result {
399 Error::from(unsafe {
400 otMessageSetLength(self.as_ot_ptr(), len.try_into().or(Err(Error::InvalidArgs))?)
403 })
404 .into()
405 }
406
407 pub fn offset(&self) -> usize {
409 unsafe { otMessageGetOffset(self.as_ot_ptr()).into() }
410 }
411
412 pub fn set_offset(&mut self, offset: usize) {
416 unsafe {
417 otMessageSetOffset(
420 self.as_ot_ptr(),
421 offset.try_into().expect("ot::Message::set_offset: Offset too large"),
422 )
423 }
424 }
425
426 pub fn set_direct_transmission(&mut self, direct_transmission: bool) {
432 unsafe {
433 otMessageSetDirectTransmission(self.as_ot_ptr(), direct_transmission);
434 }
435 }
436
437 pub fn origin(&self) -> Origin {
439 unsafe { otMessageGetOrigin(self.as_ot_ptr()) }.into()
440 }
441
442 pub fn set_origin(&mut self, origin: Origin) {
446 unsafe {
447 otMessageSetOrigin(self.as_ot_ptr(), origin.into());
448 }
449 }
450
451 pub fn rssi(&self) -> Decibels {
453 unsafe { otMessageGetRss(self.as_ot_ptr()) }
454 }
455
456 pub fn to_vec(&self) -> Vec<u8> {
459 let mut buffer = Vec::with_capacity(self.len());
460 #[allow(clippy::uninit_vec)] unsafe {
462 buffer.set_len(self.len());
463 otMessageRead(
464 self.as_ot_ptr(),
465 0,
466 buffer.as_mut_ptr() as *mut core::ffi::c_void,
467 otMessageGetLength(self.as_ot_ptr()),
468 );
469 }
470 buffer
471 }
472}
473
474#[derive(Debug, Default, Copy, Clone)]
477#[repr(transparent)]
478pub struct BufferInfo(pub otBufferInfo);
479
480impl_ot_castable!(BufferInfo, otBufferInfo);
481
482impl BufferInfo {
483 pub fn total_buffers(&self) -> u16 {
485 self.0.mTotalBuffers
486 }
487
488 pub fn free_buffers(&self) -> u16 {
490 self.0.mFreeBuffers
491 }
492
493 pub fn max_used_buffers(&self) -> u16 {
495 self.0.mMaxUsedBuffers
496 }
497
498 pub fn six_lo_send_queue(&self) -> &MessageQueueInfo {
500 unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.m6loSendQueue) }.unwrap()
501 }
502
503 pub fn six_lo_reassembly_queue(&self) -> &MessageQueueInfo {
505 unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.m6loReassemblyQueue) }.unwrap()
506 }
507
508 pub fn ip6_queue(&self) -> &MessageQueueInfo {
510 unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mIp6Queue) }.unwrap()
511 }
512
513 pub fn mpl_queue(&self) -> &MessageQueueInfo {
515 unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mMplQueue) }.unwrap()
516 }
517
518 pub fn mle_queue(&self) -> &MessageQueueInfo {
520 unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mMleQueue) }.unwrap()
521 }
522
523 pub fn coap_queue(&self) -> &MessageQueueInfo {
525 unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mCoapQueue) }.unwrap()
526 }
527
528 pub fn coap_secure_queue(&self) -> &MessageQueueInfo {
530 unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mCoapSecureQueue) }.unwrap()
531 }
532
533 pub fn application_coap_queue(&self) -> &MessageQueueInfo {
535 unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mApplicationCoapQueue) }.unwrap()
536 }
537}
538
539pub trait MessageBuffer {
541 fn get_buffer_info(&self) -> BufferInfo;
543}
544
545impl<T: MessageBuffer + Boxable> MessageBuffer for ot::Box<T> {
546 fn get_buffer_info(&self) -> BufferInfo {
547 self.as_ref().get_buffer_info()
548 }
549}
550
551impl MessageBuffer for Instance {
552 fn get_buffer_info(&self) -> BufferInfo {
553 let mut ret = BufferInfo::default();
554 unsafe {
555 otMessageGetBufferInfo(self.as_ot_ptr(), ret.as_ot_mut_ptr());
556 }
557 ret
558 }
559}
560
561#[cfg(test)]
562mod tests {
563 use super::*;
564
565 #[test]
566 fn test_origin_round_trips_through_ot_message_origin() {
567 for origin in [Origin::ThreadNetif, Origin::HostTrusted, Origin::HostUntrusted] {
568 assert_eq!(Origin::from(otMessageOrigin::from(origin)), origin);
569 }
570 }
571
572 #[test]
573 fn test_origin_matches_ot_constants() {
574 assert_eq!(otMessageOrigin::from(Origin::ThreadNetif), OT_MESSAGE_ORIGIN_THREAD_NETIF);
575 assert_eq!(otMessageOrigin::from(Origin::HostTrusted), OT_MESSAGE_ORIGIN_HOST_TRUSTED);
576 assert_eq!(otMessageOrigin::from(Origin::HostUntrusted), OT_MESSAGE_ORIGIN_HOST_UNTRUSTED);
577 }
578
579 #[test]
580 #[should_panic(expected = "Unknown otMessageOrigin value")]
581 fn test_origin_from_unknown_value_panics() {
582 let _ = Origin::from(OT_MESSAGE_ORIGIN_HOST_UNTRUSTED + 1);
583 }
584}