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]
642pub fn message_e2e_encryption_policy(ty: DataType) -> E2eEncryptionPolicy {
643 get_message_meta(ty).e2e_encryption
644}
645
646impl Mul<MessageElement> for usize {
649 type Output = usize;
650
651 #[inline]
652 fn mul(self, rhs: MessageElement) -> usize {
653 self * rhs.into()
654 }
655}
656
657impl Mul<usize> for MessageElement {
658 type Output = usize;
659
660 #[inline]
661 fn mul(self, rhs: usize) -> usize {
662 self.into() * rhs
663 }
664}
665
666impl MessageElement {
667 #[inline]
672 fn into(self) -> usize {
673 match self {
674 MessageElement::Static(a, _, _) => a,
675 _ => 0,
676 }
677 }
678}
679
680#[inline]
690pub fn get_needed_message_size(ty: DataType) -> usize {
691 data_type_size(get_data_type(ty)) * get_message_meta(ty).element
692}
693
694#[inline]
700pub fn get_info_type(ty: DataType) -> MessageClass {
701 get_message_meta(ty).element.message_type()
702}
703
704#[inline]
711pub fn get_data_type(ty: DataType) -> MessageDataType {
712 get_message_meta(ty).element.data_type()
713}
714
715#[inline]
721#[cfg(feature = "std")]
722pub fn get_message_name(ty: DataType) -> Arc<str> {
723 get_message_meta(ty).name
724}
725
726#[cfg(not(feature = "std"))]
727pub fn get_message_name(ty: DataType) -> &'static str {
728 get_message_meta(ty).name
729}
730
731#[inline]
737#[cfg(feature = "std")]
738pub fn endpoints_from_datatype(ty: DataType) -> Arc<[DataEndpoint]> {
739 get_message_meta(ty).endpoints
740}
741
742#[cfg(not(feature = "std"))]
743pub fn endpoints_from_datatype(ty: DataType) -> &'static [DataEndpoint] {
744 get_message_meta(ty).endpoints
745}
746
747#[allow(dead_code)]
752#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
753pub enum MessageDataType {
754 Float64,
755 Float32,
756 UInt8,
757 UInt16,
758 UInt32,
759 UInt64,
760 UInt128,
761 Int8,
762 Int16,
763 Int32,
764 Int64,
765 Int128,
766 Bool,
767 String,
768 Binary,
769 NoData,
770}
771
772#[inline]
781pub fn data_type_size(dt: MessageDataType) -> usize {
782 match dt {
783 MessageDataType::Float64 => size_of::<f64>(),
784 MessageDataType::Float32 => size_of::<f32>(),
785 MessageDataType::UInt8 => size_of::<u8>(),
786 MessageDataType::UInt16 => size_of::<u16>(),
787 MessageDataType::UInt32 => size_of::<u32>(),
788 MessageDataType::UInt64 => size_of::<u64>(),
789 MessageDataType::UInt128 => size_of::<u128>(),
790 MessageDataType::Int8 => size_of::<i8>(),
791 MessageDataType::Int16 => size_of::<i16>(),
792 MessageDataType::Int32 => size_of::<i32>(),
793 MessageDataType::Int64 => size_of::<i64>(),
794 MessageDataType::Int128 => size_of::<i128>(),
795 MessageDataType::Bool => size_of::<bool>(),
796 MessageDataType::String => runtime_static_string_length(),
797 MessageDataType::Binary => runtime_static_hex_length(),
798 MessageDataType::NoData => 0,
799 }
800}
801
802#[allow(dead_code)]
804#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
805pub enum MessageClass {
806 Data,
808 Error,
810 Warning,
812}
813
814#[derive(Debug, Clone, PartialEq, Eq)]
823pub enum TelemetryError {
824 GenericError(Option<Arc<str>>),
826
827 InvalidType,
829
830 SizeMismatch { expected: usize, got: usize },
832
833 SizeMismatchError,
835
836 EmptyEndpoints,
838
839 TimestampInvalid,
841
842 MissingPayload,
844
845 HandlerError(&'static str),
847
848 BadArg,
850
851 PermissionDenied,
853
854 Pack(&'static str),
856
857 Unpack(&'static str),
859
860 Io(&'static str),
862
863 InvalidUtf8,
865
866 TypeMismatch { expected: usize, got: usize },
868
869 InvalidLinkId(&'static str),
871
872 PacketTooLarge(&'static str),
874}
875
876impl TelemetryError {
877 pub const fn to_error_code(&self) -> TelemetryErrorCode {
880 match self {
881 TelemetryError::GenericError(_) => TelemetryErrorCode::GenericError,
882 TelemetryError::InvalidType => TelemetryErrorCode::InvalidType,
883 TelemetryError::SizeMismatch { .. } => TelemetryErrorCode::SizeMismatch,
884 TelemetryError::SizeMismatchError => TelemetryErrorCode::SizeMismatchError,
885 TelemetryError::EmptyEndpoints => TelemetryErrorCode::EmptyEndpoints,
886 TelemetryError::TimestampInvalid => TelemetryErrorCode::TimestampInvalid,
887 TelemetryError::MissingPayload => TelemetryErrorCode::MissingPayload,
888 TelemetryError::HandlerError(_) => TelemetryErrorCode::HandlerError,
889 TelemetryError::BadArg => TelemetryErrorCode::BadArg,
890 TelemetryError::PermissionDenied => TelemetryErrorCode::PermissionDenied,
891 TelemetryError::Pack(_) => TelemetryErrorCode::Pack,
892 TelemetryError::Unpack(_) => TelemetryErrorCode::Unpack,
893 TelemetryError::Io(_) => TelemetryErrorCode::Io,
894 TelemetryError::InvalidUtf8 => TelemetryErrorCode::InvalidUtf8,
895 TelemetryError::TypeMismatch { .. } => TelemetryErrorCode::TypeMismatch,
896 TelemetryError::InvalidLinkId(_) => TelemetryErrorCode::InvalidLinkId,
897 TelemetryError::PacketTooLarge(_) => TelemetryErrorCode::PacketTooLarge,
898 }
899 }
900}
901
902impl core::fmt::Display for TelemetryError {
904 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
905 f.write_str(&TelemetryError::to_string(self))
906 }
907}
908
909#[cfg(feature = "std")]
911impl std::error::Error for TelemetryError {
912 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
913 None
914 }
915}
916
917#[cfg(feature = "std")]
919impl From<Error> for TelemetryError {
920 fn from(error: Error) -> Self {
921 let str = error.to_string();
922 let astr: Arc<str> = Arc::from(str.as_str());
923 TelemetryError::GenericError(Some(astr))
924 }
925}
926
927#[cfg(feature = "std")]
929impl From<Box<dyn std::error::Error>> for TelemetryError {
930 fn from(err: Box<dyn std::error::Error>) -> Self {
931 let str = err.to_string();
932 let astr: Arc<str> = Arc::from(str.as_str());
933 TelemetryError::GenericError(Some(astr))
934 }
935}
936
937#[derive(Debug, Clone, Copy, PartialEq, Eq)]
942#[repr(i32)]
943pub enum TelemetryErrorCode {
944 GenericError = -2,
945 InvalidType = -3,
946 SizeMismatch = -4,
947 SizeMismatchError = -5,
948 EmptyEndpoints = -6,
949 TimestampInvalid = -7,
950 MissingPayload = -8,
951 HandlerError = -9,
952 BadArg = -10,
953 PermissionDenied = -11,
954 Pack = -12,
955 Unpack = -13,
956 Io = -14,
957 InvalidUtf8 = -15,
958 TypeMismatch = -16,
959 InvalidLinkId = -17,
960 PacketTooLarge = -18,
961}
962
963impl_repr_i32_enum!(
965 TelemetryErrorCode,
966 TelemetryErrorCode::MAX,
967 TelemetryErrorCode::MIN
968);
969
970impl TelemetryErrorCode {
971 pub const MAX: i32 = TelemetryErrorCode::InvalidType as i32;
973
974 pub const MIN: i32 = TelemetryErrorCode::PacketTooLarge as i32;
976
977 #[inline]
981 pub fn as_str(&self) -> &'static str {
982 match self {
983 TelemetryErrorCode::GenericError => "GenericError",
984 TelemetryErrorCode::InvalidType => "{Invalid Type}",
985 TelemetryErrorCode::SizeMismatch => "{Size Mismatch}",
986 TelemetryErrorCode::SizeMismatchError => "{Size Mismatch Error}",
987 TelemetryErrorCode::EmptyEndpoints => "{Empty Endpoints}",
988 TelemetryErrorCode::TimestampInvalid => "{Timestamp Invalid}",
989 TelemetryErrorCode::MissingPayload => "{Missing Payload}",
990 TelemetryErrorCode::HandlerError => "{Handler Error}",
991 TelemetryErrorCode::BadArg => "{Bad Arg}",
992 TelemetryErrorCode::PermissionDenied => "{Permission Denied}",
993 TelemetryErrorCode::Pack => "{Pack Error}",
994 TelemetryErrorCode::Unpack => "{Unpack Error}",
995 TelemetryErrorCode::Io => "{IO Error}",
996 TelemetryErrorCode::InvalidUtf8 => "{Invalid UTF-8}",
997 TelemetryErrorCode::TypeMismatch => "{Type Mismatch}",
998 TelemetryErrorCode::InvalidLinkId => "{Invalid Link ID}",
999 TelemetryErrorCode::PacketTooLarge => "{Packet Too Large}",
1000 }
1001 }
1002
1003 #[inline]
1011 pub fn try_from_i32(x: i32) -> Option<Self> {
1012 try_enum_from_i32(x)
1013 }
1014}
1015
1016pub type TelemetryResult<T> = Result<T, TelemetryError>;
1018
1019#[inline]
1031pub fn try_enum_from_u32<E: ReprU32Enum>(x: u32) -> Option<E> {
1032 if x > E::MAX {
1033 return None;
1034 }
1035 E::from_u32(x)
1036}
1037
1038#[inline]
1046pub fn try_enum_from_i32<E: ReprI32Enum>(x: i32) -> Option<E> {
1047 if x < E::MIN || x > E::MAX {
1048 return None;
1049 }
1050
1051 let e = unsafe { (&x as *const i32 as *const E).read() };
1053 Some(e)
1054}