1#![cfg_attr(not(feature = "std"), no_std)]
12#![allow(unused_doc_comments)]
13extern crate alloc;
35
36extern crate core;
37#[cfg(feature = "std")]
38extern crate std;
39#[cfg(feature = "std")]
40use std::io::Error;
41
42use crate::config::{
43 DataEndpoint, DataType, get_endpoint_meta, get_message_meta, max_data_type_id, max_endpoint_id,
44 runtime_static_hex_length, runtime_static_string_length,
45};
46use crate::macros::{ReprI32Enum, ReprU32Enum};
47use alloc::string::ToString;
48use alloc::sync::Arc;
49use core::fmt::Formatter;
50use core::mem::size_of;
51use core::ops::Mul;
52
53#[cfg(all(test, feature = "std"))]
58mod tests;
59
60#[cfg(feature = "python")]
61#[cfg(feature = "std")]
62mod python_api;
63
64#[cfg(all(not(feature = "std"), target_os = "none"))]
72unsafe extern "C" {
73 fn seds_error_msg(msg: *const u8, len: usize);
74}
75
76#[cfg(all(not(feature = "std"), target_os = "none"))]
77mod embedded_alloc {
78 use core::alloc::{GlobalAlloc, Layout};
79 use core::mem::size_of;
80
81 unsafe extern "C" {
82 fn telemetryMalloc(size: usize) -> *mut core::ffi::c_void;
83 fn telemetryFree(ptr: *mut core::ffi::c_void);
84 fn telemetry_panic_hook(msg: *const u8, len: usize);
85 }
86
87 struct TelemetryAlloc;
90
91 #[inline]
92 fn align_up(addr: usize, align: usize) -> usize {
93 (addr + (align - 1)) & !(align - 1)
94 }
95
96 unsafe impl GlobalAlloc for TelemetryAlloc {
97 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
98 let align = layout.align().max(size_of::<usize>());
99 let header = size_of::<usize>();
100 let total = match layout
101 .size()
102 .checked_add(align)
103 .and_then(|v| v.checked_add(header))
104 {
105 Some(v) => v,
106 None => return core::ptr::null_mut(),
107 };
108
109 let raw = unsafe { telemetryMalloc(total) as *mut u8 };
110 if raw.is_null() {
111 return core::ptr::null_mut();
112 }
113
114 let base = raw as usize + header;
115 let aligned = align_up(base, align) as *mut u8;
116
117 unsafe {
119 let slot = (aligned as *mut usize).offset(-1);
120 *slot = raw as usize;
121 }
122
123 aligned
124 }
125
126 unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
127 if ptr.is_null() {
128 return;
129 }
130
131 let raw = unsafe {
132 let slot = (ptr as *mut usize).offset(-1);
133 *slot as *mut core::ffi::c_void
134 };
135 unsafe { telemetryFree(raw) };
136 }
137 }
138
139 #[global_allocator]
140 static A: TelemetryAlloc = TelemetryAlloc;
141
142 use core::panic::PanicInfo;
144
145 #[panic_handler]
146 fn panic(_info: &PanicInfo) -> ! {
147 let msg = b"rust panic";
148 unsafe {
149 telemetry_panic_hook(msg.as_ptr(), msg.len());
150 }
151
152 loop {}
154 }
155
156 }
159
160mod c_api;
168pub mod config;
169#[cfg(feature = "cryptography")]
170pub mod crypto;
171pub mod diagnostics;
172#[cfg(feature = "discovery")]
173pub mod discovery;
174mod lock;
175mod macros;
176pub mod packet;
177mod queue;
178pub mod relay;
179pub mod router;
180mod small_payload;
181#[cfg(feature = "timesync")]
182pub mod timesync;
183pub mod wire_format;
184pub const MAX_VALUE_DATA_ENDPOINT: u32 = 255;
190
191pub const MAX_VALUE_DATA_TYPE: u32 = 4095;
193
194pub const MAX_VALUE_ROUTE_SELECTION_MODE: i32 = 2;
196
197impl ReprU32Enum for DataType {
198 const MAX: u32 = MAX_VALUE_DATA_TYPE;
199
200 #[inline]
201 fn from_u32(x: u32) -> Option<Self> {
202 DataType::try_from_u32(x)
203 }
204}
205
206impl ReprU32Enum for DataEndpoint {
207 const MAX: u32 = MAX_VALUE_DATA_ENDPOINT;
208
209 #[inline]
210 fn from_u32(x: u32) -> Option<Self> {
211 DataEndpoint::try_from_u32(x)
212 }
213}
214
215#[inline]
216pub fn current_max_endpoint_id() -> u32 {
217 max_endpoint_id()
218}
219
220#[inline]
221pub fn current_max_data_type_id() -> u32 {
222 max_data_type_id()
223}
224
225#[repr(i32)]
226#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
227pub enum RouteSelectionMode {
228 Fanout = 0,
229 Weighted = 1,
230 Failover = 2,
231}
232
233impl_repr_i32_enum!(
234 RouteSelectionMode,
235 RouteSelectionMode::Fanout as i32,
236 RouteSelectionMode::Failover as i32
237);
238
239#[inline]
240const fn parse_usize(s: &str) -> usize {
241 let bytes = s.as_bytes();
242 let mut i = 0;
243 let mut val = 0;
244
245 while i < bytes.len() {
246 let c = bytes[i];
247 if c < b'0' || c > b'9' {
248 panic!("Invalid digit");
249 }
250 val = val * 10 + (c - b'0') as usize;
251 i += 1;
252 }
253 val
254}
255
256#[inline]
257pub const fn parse_f64(s: &str) -> f64 {
258 let bytes = s.as_bytes();
259 let mut i = 0;
260
261 if bytes.is_empty() {
262 panic!("empty string");
263 }
264
265 let mut sign = 1.0;
267 if bytes[i] == b'-' {
268 sign = -1.0;
269 i += 1;
270 } else if bytes[i] == b'+' {
271 i += 1;
272 }
273
274 let mut int_part: f64 = 0.0;
275 let mut has_digits = false;
276
277 while i < bytes.len() && bytes[i] >= b'0' && bytes[i] <= b'9' {
278 int_part = int_part * 10.0 + (bytes[i] - b'0') as f64;
279 i += 1;
280 has_digits = true;
281 }
282
283 let mut frac_part: f64 = 0.0;
284 let mut scale: f64 = 1.0;
285
286 if i < bytes.len() && bytes[i] == b'.' {
287 i += 1;
288
289 while i < bytes.len() && bytes[i] >= b'0' && bytes[i] <= b'9' {
290 scale *= 10.0;
291 frac_part += (bytes[i] - b'0') as f64 / scale;
292 i += 1;
293 has_digits = true;
294 }
295 }
296
297 if !has_digits || i != bytes.len() {
298 panic!("invalid f64 literal");
299 }
300
301 sign * (int_part + frac_part)
302}
303
304#[inline(always)]
305const fn parse_strings(s: &str) -> &str {
306 s
307}
308
309#[inline]
310pub const fn parse_u8(s: &str) -> u8 {
311 let bytes = s.as_bytes();
312 let mut i = 0;
313 let mut val: u16 = 0;
314
315 if bytes.is_empty() {
316 panic!("empty string");
317 }
318
319 while i < bytes.len() {
320 let c = bytes[i];
321 if c < b'0' || c > b'9' {
322 panic!("invalid digit in u8");
323 }
324
325 val = val * 10 + (c - b'0') as u16;
326 if val > 255 {
327 panic!("u8 overflow");
328 }
329
330 i += 1;
331 }
332
333 val as u8
334}
335
336#[inline]
337pub const fn parse_u128(s: &str) -> u128 {
338 let bytes = s.as_bytes();
339 let mut i = 0;
340 let mut val: u128 = 0;
341
342 if bytes.is_empty() {
343 panic!("empty string");
344 }
345
346 while i < bytes.len() {
347 let c = bytes[i];
348 if c < b'0' || c > b'9' {
349 panic!("invalid digit in u128");
350 }
351
352 let digit = (c - b'0') as u128;
353
354 if val > (u128::MAX - digit) / 10 {
357 panic!("u128 overflow");
358 }
359
360 val = val * 10 + digit;
361 i += 1;
362 }
363
364 val
365}
366
367#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
371pub struct EndpointMeta {
372 #[cfg(feature = "std")]
374 name: Arc<str>,
375 #[cfg(not(feature = "std"))]
376 name: &'static str,
377 #[cfg(feature = "std")]
379 description: Arc<str>,
380 #[cfg(not(feature = "std"))]
381 description: &'static str,
382 link_local_only: bool,
384}
385
386impl EndpointMeta {
387 #[cfg(feature = "std")]
388 pub(crate) fn name_ref(&self) -> &str {
389 self.name.as_ref()
390 }
391
392 #[cfg(not(feature = "std"))]
393 pub(crate) fn name_ref(&self) -> &str {
394 self.name
395 }
396
397 #[cfg(feature = "std")]
398 pub(crate) fn description_ref(&self) -> &str {
399 self.description.as_ref()
400 }
401
402 #[cfg(not(feature = "std"))]
403 pub(crate) fn description_ref(&self) -> &str {
404 self.description
405 }
406
407 #[cfg(feature = "std")]
413 pub fn as_str(&self) -> Arc<str> {
414 self.name.clone()
415 }
416
417 #[cfg(not(feature = "std"))]
418 pub fn as_str(&self) -> &'static str {
419 self.name
420 }
421
422 #[inline]
424 #[cfg(feature = "std")]
425 pub fn description(&self) -> Arc<str> {
426 self.description.clone()
427 }
428
429 #[cfg(not(feature = "std"))]
430 pub fn description(&self) -> &'static str {
431 self.description
432 }
433
434 #[inline]
436 pub fn is_link_local_only(&self) -> bool {
437 self.link_local_only
438 }
439}
440
441impl DataEndpoint {
442 #[cfg(feature = "std")]
448 pub fn as_str(&self) -> Arc<str> {
449 get_endpoint_meta(*self).name
450 }
451
452 #[cfg(not(feature = "std"))]
453 pub fn as_str(&self) -> &'static str {
454 get_endpoint_meta(*self).name
455 }
456
457 #[cfg(feature = "std")]
459 pub fn description(&self) -> Arc<str> {
460 get_endpoint_meta(*self).description
461 }
462
463 #[cfg(not(feature = "std"))]
464 pub fn description(&self) -> &'static str {
465 get_endpoint_meta(*self).description
466 }
467
468 #[inline]
470 pub fn is_link_local_only(&self) -> bool {
471 get_endpoint_meta(*self).link_local_only
472 }
473}
474
475#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
477pub enum MessageElement {
478 Static(usize, MessageDataType, MessageClass),
482 Dynamic(MessageDataType, MessageClass),
486}
487
488impl MessageElement {
489 #[inline]
491 pub const fn data_type(&self) -> MessageDataType {
492 match self {
493 MessageElement::Static(_, dt, _) => *dt,
494 MessageElement::Dynamic(dt, _) => *dt,
495 }
496 }
497
498 #[inline]
500 pub const fn message_type(&self) -> MessageClass {
501 match self {
502 MessageElement::Static(_, _, mt) => *mt,
503 MessageElement::Dynamic(_, mt) => *mt,
504 }
505 }
506}
507
508#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
510pub enum ReliableMode {
511 None,
513 Ordered,
515 Unordered,
517}
518
519#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
521pub enum E2eEncryptionPolicy {
522 PreferOff,
524 PreferOn,
526 RequireOn,
528}
529
530#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
532pub struct MessageMeta {
533 #[cfg(feature = "std")]
534 name: Arc<str>,
535 #[cfg(not(feature = "std"))]
536 name: &'static str,
537 #[cfg(feature = "std")]
539 description: Arc<str>,
540 #[cfg(not(feature = "std"))]
541 description: &'static str,
542 element: MessageElement,
544 #[cfg(feature = "std")]
546 endpoints: Arc<[DataEndpoint]>,
547 #[cfg(not(feature = "std"))]
548 endpoints: &'static [DataEndpoint],
549 reliable: ReliableMode,
551 priority: u8,
553 e2e_encryption: E2eEncryptionPolicy,
555}
556
557impl MessageMeta {
558 #[cfg(feature = "std")]
559 pub(crate) fn name_ref(&self) -> &str {
560 self.name.as_ref()
561 }
562
563 #[cfg(not(feature = "std"))]
564 pub(crate) fn name_ref(&self) -> &str {
565 self.name
566 }
567
568 #[cfg(feature = "std")]
569 pub(crate) fn description_ref(&self) -> &str {
570 self.description.as_ref()
571 }
572
573 #[cfg(not(feature = "std"))]
574 pub(crate) fn description_ref(&self) -> &str {
575 self.description
576 }
577
578 #[cfg(feature = "std")]
579 pub(crate) fn endpoints_ref(&self) -> &[DataEndpoint] {
580 self.endpoints.as_ref()
581 }
582
583 #[cfg(not(feature = "std"))]
584 pub(crate) fn endpoints_ref(&self) -> &[DataEndpoint] {
585 self.endpoints
586 }
587}
588
589impl DataType {
590 #[cfg(feature = "std")]
592 pub fn as_str(&self) -> Arc<str> {
593 get_message_meta(*self).name
594 }
595
596 #[cfg(not(feature = "std"))]
597 pub fn as_str(&self) -> &'static str {
598 get_message_meta(*self).name
599 }
600
601 #[cfg(feature = "std")]
603 pub fn description(&self) -> Arc<str> {
604 get_message_meta(*self).description
605 }
606
607 #[cfg(not(feature = "std"))]
608 pub fn description(&self) -> &'static str {
609 get_message_meta(*self).description
610 }
611}
612#[inline]
618pub fn message_meta(ty: DataType) -> MessageMeta {
619 get_message_meta(ty)
620}
621
622#[inline]
624pub fn is_reliable_type(ty: DataType) -> bool {
625 !matches!(get_message_meta(ty).reliable, ReliableMode::None)
626}
627
628#[inline]
630pub fn reliable_mode(ty: DataType) -> ReliableMode {
631 get_message_meta(ty).reliable
632}
633
634#[inline]
636pub fn message_priority(ty: DataType) -> u8 {
637 get_message_meta(ty).priority
638}
639
640#[inline]
648pub fn transport_priority(ty: DataType) -> u8 {
649 match ty {
650 DataType::ReliableAck | DataType::ReliablePartialAck | DataType::ReliablePacketRequest => {
653 255
654 }
655
656 DataType::DiscoveryAnnounce
658 | DataType::DiscoveryTimeSyncSources
659 | DataType::DiscoveryTopology
660 | DataType::DiscoverySchema
661 | DataType::DiscoveryTopologyRequest
662 | DataType::DiscoverySchemaRequest
663 | DataType::DiscoveryLeave
664 | DataType::DiscoveryLinkCapabilities
665 | DataType::DiscoveryAddress => 255,
666
667 DataType::ManagedVariableRequest
669 | DataType::ManagedVariableValue
670 | DataType::TimeSyncAnnounce
671 | DataType::TimeSyncRequest
672 | DataType::TimeSyncResponse => 254,
673
674 _ => message_priority(ty).min(253),
676 }
677}
678
679#[inline]
682pub(crate) fn scheduler_priority(ty: DataType) -> u8 {
683 transport_priority(ty)
684}
685
686#[inline]
688pub fn message_e2e_encryption_policy(ty: DataType) -> E2eEncryptionPolicy {
689 get_message_meta(ty).e2e_encryption
690}
691
692impl Mul<MessageElement> for usize {
695 type Output = usize;
696
697 #[inline]
698 fn mul(self, rhs: MessageElement) -> usize {
699 self * rhs.into()
700 }
701}
702
703impl Mul<usize> for MessageElement {
704 type Output = usize;
705
706 #[inline]
707 fn mul(self, rhs: usize) -> usize {
708 self.into() * rhs
709 }
710}
711
712impl MessageElement {
713 #[inline]
718 fn into(self) -> usize {
719 match self {
720 MessageElement::Static(a, _, _) => a,
721 _ => 0,
722 }
723 }
724}
725
726#[inline]
736pub fn get_needed_message_size(ty: DataType) -> usize {
737 data_type_size(get_data_type(ty)) * get_message_meta(ty).element
738}
739
740#[inline]
746pub fn get_info_type(ty: DataType) -> MessageClass {
747 get_message_meta(ty).element.message_type()
748}
749
750#[inline]
757pub fn get_data_type(ty: DataType) -> MessageDataType {
758 get_message_meta(ty).element.data_type()
759}
760
761#[inline]
767#[cfg(feature = "std")]
768pub fn get_message_name(ty: DataType) -> Arc<str> {
769 get_message_meta(ty).name
770}
771
772#[cfg(not(feature = "std"))]
773pub fn get_message_name(ty: DataType) -> &'static str {
774 get_message_meta(ty).name
775}
776
777#[inline]
783#[cfg(feature = "std")]
784pub fn endpoints_from_datatype(ty: DataType) -> Arc<[DataEndpoint]> {
785 get_message_meta(ty).endpoints
786}
787
788#[cfg(not(feature = "std"))]
789pub fn endpoints_from_datatype(ty: DataType) -> &'static [DataEndpoint] {
790 get_message_meta(ty).endpoints
791}
792
793#[allow(dead_code)]
798#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
799pub enum MessageDataType {
800 Float64,
801 Float32,
802 UInt8,
803 UInt16,
804 UInt32,
805 UInt64,
806 UInt128,
807 Int8,
808 Int16,
809 Int32,
810 Int64,
811 Int128,
812 Bool,
813 String,
814 Binary,
815 NoData,
816}
817
818#[inline]
827pub fn data_type_size(dt: MessageDataType) -> usize {
828 match dt {
829 MessageDataType::Float64 => size_of::<f64>(),
830 MessageDataType::Float32 => size_of::<f32>(),
831 MessageDataType::UInt8 => size_of::<u8>(),
832 MessageDataType::UInt16 => size_of::<u16>(),
833 MessageDataType::UInt32 => size_of::<u32>(),
834 MessageDataType::UInt64 => size_of::<u64>(),
835 MessageDataType::UInt128 => size_of::<u128>(),
836 MessageDataType::Int8 => size_of::<i8>(),
837 MessageDataType::Int16 => size_of::<i16>(),
838 MessageDataType::Int32 => size_of::<i32>(),
839 MessageDataType::Int64 => size_of::<i64>(),
840 MessageDataType::Int128 => size_of::<i128>(),
841 MessageDataType::Bool => size_of::<bool>(),
842 MessageDataType::String => runtime_static_string_length(),
843 MessageDataType::Binary => runtime_static_hex_length(),
844 MessageDataType::NoData => 0,
845 }
846}
847
848#[allow(dead_code)]
850#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
851pub enum MessageClass {
852 Data,
854 Error,
856 Warning,
858}
859
860#[derive(Debug, Clone, PartialEq, Eq)]
869pub enum TelemetryError {
870 GenericError(Option<Arc<str>>),
872
873 InvalidType,
875
876 SizeMismatch { expected: usize, got: usize },
878
879 SizeMismatchError,
881
882 EmptyEndpoints,
884
885 TimestampInvalid,
887
888 MissingPayload,
890
891 HandlerError(&'static str),
893
894 BadArg,
896
897 PermissionDenied,
899
900 Pack(&'static str),
902
903 Unpack(&'static str),
905
906 Io(&'static str),
908
909 InvalidUtf8,
911
912 TypeMismatch { expected: usize, got: usize },
914
915 InvalidLinkId(&'static str),
917
918 PacketTooLarge(&'static str),
920}
921
922impl TelemetryError {
923 pub const fn to_error_code(&self) -> TelemetryErrorCode {
926 match self {
927 TelemetryError::GenericError(_) => TelemetryErrorCode::GenericError,
928 TelemetryError::InvalidType => TelemetryErrorCode::InvalidType,
929 TelemetryError::SizeMismatch { .. } => TelemetryErrorCode::SizeMismatch,
930 TelemetryError::SizeMismatchError => TelemetryErrorCode::SizeMismatchError,
931 TelemetryError::EmptyEndpoints => TelemetryErrorCode::EmptyEndpoints,
932 TelemetryError::TimestampInvalid => TelemetryErrorCode::TimestampInvalid,
933 TelemetryError::MissingPayload => TelemetryErrorCode::MissingPayload,
934 TelemetryError::HandlerError(_) => TelemetryErrorCode::HandlerError,
935 TelemetryError::BadArg => TelemetryErrorCode::BadArg,
936 TelemetryError::PermissionDenied => TelemetryErrorCode::PermissionDenied,
937 TelemetryError::Pack(_) => TelemetryErrorCode::Pack,
938 TelemetryError::Unpack(_) => TelemetryErrorCode::Unpack,
939 TelemetryError::Io(_) => TelemetryErrorCode::Io,
940 TelemetryError::InvalidUtf8 => TelemetryErrorCode::InvalidUtf8,
941 TelemetryError::TypeMismatch { .. } => TelemetryErrorCode::TypeMismatch,
942 TelemetryError::InvalidLinkId(_) => TelemetryErrorCode::InvalidLinkId,
943 TelemetryError::PacketTooLarge(_) => TelemetryErrorCode::PacketTooLarge,
944 }
945 }
946}
947
948impl core::fmt::Display for TelemetryError {
950 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
951 f.write_str(&TelemetryError::to_string(self))
952 }
953}
954
955#[cfg(feature = "std")]
957impl std::error::Error for TelemetryError {
958 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
959 None
960 }
961}
962
963#[cfg(feature = "std")]
965impl From<Error> for TelemetryError {
966 fn from(error: Error) -> Self {
967 let str = error.to_string();
968 let astr: Arc<str> = Arc::from(str.as_str());
969 TelemetryError::GenericError(Some(astr))
970 }
971}
972
973#[cfg(feature = "std")]
975impl From<Box<dyn std::error::Error>> for TelemetryError {
976 fn from(err: Box<dyn std::error::Error>) -> Self {
977 let str = err.to_string();
978 let astr: Arc<str> = Arc::from(str.as_str());
979 TelemetryError::GenericError(Some(astr))
980 }
981}
982
983#[derive(Debug, Clone, Copy, PartialEq, Eq)]
988#[repr(i32)]
989pub enum TelemetryErrorCode {
990 GenericError = -2,
991 InvalidType = -3,
992 SizeMismatch = -4,
993 SizeMismatchError = -5,
994 EmptyEndpoints = -6,
995 TimestampInvalid = -7,
996 MissingPayload = -8,
997 HandlerError = -9,
998 BadArg = -10,
999 PermissionDenied = -11,
1000 Pack = -12,
1001 Unpack = -13,
1002 Io = -14,
1003 InvalidUtf8 = -15,
1004 TypeMismatch = -16,
1005 InvalidLinkId = -17,
1006 PacketTooLarge = -18,
1007}
1008
1009impl_repr_i32_enum!(
1011 TelemetryErrorCode,
1012 TelemetryErrorCode::MAX,
1013 TelemetryErrorCode::MIN
1014);
1015
1016impl TelemetryErrorCode {
1017 pub const MAX: i32 = TelemetryErrorCode::InvalidType as i32;
1019
1020 pub const MIN: i32 = TelemetryErrorCode::PacketTooLarge as i32;
1022
1023 #[inline]
1027 pub fn as_str(&self) -> &'static str {
1028 match self {
1029 TelemetryErrorCode::GenericError => "GenericError",
1030 TelemetryErrorCode::InvalidType => "{Invalid Type}",
1031 TelemetryErrorCode::SizeMismatch => "{Size Mismatch}",
1032 TelemetryErrorCode::SizeMismatchError => "{Size Mismatch Error}",
1033 TelemetryErrorCode::EmptyEndpoints => "{Empty Endpoints}",
1034 TelemetryErrorCode::TimestampInvalid => "{Timestamp Invalid}",
1035 TelemetryErrorCode::MissingPayload => "{Missing Payload}",
1036 TelemetryErrorCode::HandlerError => "{Handler Error}",
1037 TelemetryErrorCode::BadArg => "{Bad Arg}",
1038 TelemetryErrorCode::PermissionDenied => "{Permission Denied}",
1039 TelemetryErrorCode::Pack => "{Pack Error}",
1040 TelemetryErrorCode::Unpack => "{Unpack Error}",
1041 TelemetryErrorCode::Io => "{IO Error}",
1042 TelemetryErrorCode::InvalidUtf8 => "{Invalid UTF-8}",
1043 TelemetryErrorCode::TypeMismatch => "{Type Mismatch}",
1044 TelemetryErrorCode::InvalidLinkId => "{Invalid Link ID}",
1045 TelemetryErrorCode::PacketTooLarge => "{Packet Too Large}",
1046 }
1047 }
1048
1049 #[inline]
1057 pub fn try_from_i32(x: i32) -> Option<Self> {
1058 try_enum_from_i32(x)
1059 }
1060}
1061
1062pub type TelemetryResult<T> = Result<T, TelemetryError>;
1064
1065#[inline]
1077pub fn try_enum_from_u32<E: ReprU32Enum>(x: u32) -> Option<E> {
1078 if x > E::MAX {
1079 return None;
1080 }
1081 E::from_u32(x)
1082}
1083
1084#[inline]
1092pub fn try_enum_from_i32<E: ReprI32Enum>(x: i32) -> Option<E> {
1093 if x < E::MIN || x > E::MAX {
1094 return None;
1095 }
1096
1097 let e = unsafe { (&x as *const i32 as *const E).read() };
1099 Some(e)
1100}