someip_wire/
lib.rs

1//! # SOME/IP-wire
2//!
3//! This crate provides the means for parsing byte arrays into higher-level
4//! SOME/IP representations, and vice versa. It is designed to be used in embedded
5//! environments and is a `no_std` crate by default.
6//!
7//! ## Scope
8//!
9//! **This crate focuses solely on SOME/IP header parsing and serialization.**
10//!
11//! The crate parses the standardized 16-byte SOME/IP header and provides the payload
12//! data as a raw byte slice. It does NOT parse the payload content itself, as payload
13//! format is entirely application-specific and defined by service interface definitions
14//! (e.g., FIDL/Franca IDL).
15//!
16//! To use this crate in a complete SOME/IP stack, you need to:
17//! 1. Use this crate to parse/emit SOME/IP headers
18//! 2. Implement your own payload parser/serializer based on your service definitions
19//! 3. Connect service/method IDs to their respective payload handlers
20//!
21//! This separation keeps the crate focused, lightweight, and universally applicable
22//! across different SOME/IP service implementations.
23//!
24//! ## Features
25//!
26//! - `no_std` compatible by default
27//! - Zero-allocation parsing and serialization
28//! - Support for all SOME/IP message types
29//! - Clean enum-based API for return codes and message types
30//! - Wire format using simple u8 for efficiency
31//!
32//! ## Examples
33//!
34//! ### Parsing a SOME/IP packet
35//!
36//! ```rust
37//! use someip_wire::packet::Packet;
38//! use someip_wire::payload::Repr;
39//! use someip_wire::types::{MessageId, RequestId, MessageType, ReturnCode};
40//!
41//! // Example SOME/IP packet bytes (16-byte header + payload)
42//! let buffer = [
43//!     0x12, 0x34, 0x00, 0x01, // Message ID (service 0x1234, method 0x0001)
44//!     0x00, 0x00, 0x00, 0x10, // Length
45//!     0x00, 0x01, 0x00, 0x00, // Request ID (client 0x0001, session 0x0000)
46//!     0x01,                   // Protocol version
47//!     0x01,                   // Interface version
48//!     0x00,                   // Message type (Request)
49//!     0x00,                   // Return code (E_OK)
50//!     // Payload data follows...
51//!     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
52//! ];
53//!
54//! let packet = Packet::new_unchecked(&buffer);
55//! let repr = Repr::parse(&packet).unwrap();
56//!
57//! assert_eq!(repr.message_type, MessageType::Request);
58//! assert_eq!(repr.return_code, ReturnCode::E_OK);
59//! assert_eq!(repr.protocol_version, 0x01);
60//! assert_eq!(repr.data.len(), 8);
61//! ```
62//!
63//! ### Creating and emitting a SOME/IP packet
64//!
65//! ```rust
66//! use someip_wire::packet::Packet;
67//! use someip_wire::payload::Repr;
68//! use someip_wire::types::{MessageId, RequestId, ClientId, MessageType, ReturnCode};
69//!
70//! // Use Repr::new() to automatically calculate the length field
71//! let repr = Repr::new(
72//!     MessageId { service_id: 0x1234, method_id: 0x0001 },
73//!     RequestId {
74//!         client_id: ClientId { client_id_prefix: 0x00, client_id: 0x01 },
75//!         session_id: 0x0000,
76//!     },
77//!     0x01, // protocol_version
78//!     0x01, // interface_version
79//!     MessageType::Response,
80//!     ReturnCode::E_OK,
81//!     &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
82//! );
83//!
84//! // The length field is automatically set to 16 (8 header + 8 payload)
85//! assert_eq!(repr.length, 16);
86//!
87//! let mut buffer = [0u8; 24]; // 16-byte header + 8-byte payload
88//! let mut packet = Packet::new_unchecked(&mut buffer);
89//! repr.emit(&mut packet);
90//!
91//! assert_eq!(packet.message_type(), 0x03); // Response
92//! assert_eq!(packet.return_code(), 0x00); // E_OK
93//! ```
94//!
95//! ### Working with return codes
96//!
97//! ```rust
98//! use someip_wire::types::ReturnCode;
99//!
100//! // Named return codes
101//! let ok = ReturnCode::E_OK;
102//! let error = ReturnCode::E_NOT_OK;
103//! let timeout = ReturnCode::E_TIMEOUT;
104//!
105//! // Reserved ranges
106//! let someip_reserved = ReturnCode::ReservedSomeIP(0x15);
107//! let service_reserved = ReturnCode::ReservedServiceMethod(0x30);
108//!
109//! // Convert to/from u8
110//! assert_eq!(ok.as_u8(), 0x00);
111//! assert_eq!(ReturnCode::from_u8(0x01), Some(ReturnCode::E_NOT_OK));
112//!
113//! // Check return code properties
114//! assert!(ok.is_ok());
115//! assert!(someip_reserved.is_reserved_someip());
116//! assert!(service_reserved.is_reserved_service_method());
117//! ```
118//!
119//! ## Modules
120//!
121//! - `error`: Contains the error type for SOME/IP packet parsing
122//! - `field`: Contains the field definitions for the SOME/IP header
123//! - `packet`: Contains the `Packet` type for low-level packet access (wire format)
124//! - `payload`: Contains the `Repr` type for high-level SOME/IP representation
125//! - `types`: Contains SOME/IP type definitions (MessageId, RequestId, ReturnCode, MessageType)
126//!
127//! ## Architecture
128//!
129//! The crate uses a two-layer architecture:
130//! - **Wire format layer** (`packet`): Works directly with u8 values for efficiency
131//! - **Representation layer** (`payload`, `types`): Provides clean enums and type-safe APIs
132//!
133//! This design ensures zero-cost abstractions while maintaining a pleasant developer experience.
134//!
135
136#![no_std]
137
138pub mod error;
139pub mod field;
140pub mod packet;
141pub mod payload;
142pub mod types;
143
144#[cfg(test)]
145mod tests {
146    use crate::{
147        packet::Packet,
148        payload::Repr,
149        types::{ClientId, MessageId, MessageType, RequestId, ReturnCode},
150    };
151
152    #[test]
153    fn test_deconstruct_without_payload() {
154        let raw_packet: [u8; 16] = [
155            0x12, 0x34, 0x00, 0x01, // Message ID
156            0x00, 0x00, 0x00, 0x08, // Length (8 header bytes, no payload)
157            0x01, 0x02, 0x00, 0x01, // Request ID
158            0x01, // Protocol Version
159            0x01, // Interface Version
160            0x00, // Message Type
161            0x00, // Return Code
162        ];
163
164        let packet = Packet::new_checked(&raw_packet[..]).unwrap();
165        let repr = Repr::parse(&packet).unwrap();
166
167        assert_eq!(
168            repr.message_id,
169            MessageId {
170                service_id: 0x1234,
171                method_id: 0x0001,
172            }
173        );
174        assert_eq!(repr.length, 8); // 8 header bytes, no payload
175
176        assert_eq!(
177            repr.request_id,
178            RequestId {
179                client_id: ClientId {
180                    client_id_prefix: 0x01,
181                    client_id: 0x02,
182                },
183                session_id: 0x0001,
184            }
185        );
186        assert_eq!(repr.protocol_version, 0x01);
187        assert_eq!(repr.interface_version, 0x01);
188        assert_eq!(repr.message_type, MessageType::Request);
189        assert_eq!(repr.return_code, ReturnCode::E_OK);
190        assert_eq!(repr.data, &[]);
191    }
192
193    #[test]
194    fn test_deconstruct_with_payload() {
195        let raw_packet: [u8; 20] = [
196            0x12, 0x34, 0x00, 0x01, // Message ID
197            0x00, 0x00, 0x00, 0x0C, // Length (8 header bytes + 4 payload bytes)
198            0x01, 0x02, 0x00, 0x01, // Request ID
199            0x01, // Protocol Version
200            0x01, // Interface Version
201            0x00, // Message Type
202            0x00, // Return Code
203            0xDE, 0xAD, 0xBE, 0xEF, // Payload
204        ];
205
206        let packet = Packet::new_checked(&raw_packet[..]).unwrap();
207        let repr = Repr::parse(&packet).unwrap();
208
209        assert_eq!(
210            repr.message_id,
211            MessageId {
212                service_id: 0x1234,
213                method_id: 0x0001,
214            }
215        );
216        assert_eq!(repr.length, 12); // 8 header bytes + 4 payload bytes
217
218        assert_eq!(
219            repr.request_id,
220            RequestId {
221                client_id: ClientId {
222                    client_id_prefix: 0x01,
223                    client_id: 0x02,
224                },
225                session_id: 0x0001,
226            }
227        );
228        assert_eq!(repr.protocol_version, 0x01);
229        assert_eq!(repr.interface_version, 0x01);
230        assert_eq!(repr.message_type, MessageType::Request);
231        assert_eq!(repr.return_code, ReturnCode::E_OK);
232        assert_eq!(repr.data, &[0xDE, 0xAD, 0xBE, 0xEF]);
233    }
234
235    #[test]
236    fn test_repr_parse() {
237        let raw_packet: [u8; 16] = [
238            0x12, 0x34, 0x00, 0x01, // Message ID
239            0x00, 0x00, 0x00, 0x08, // Length
240            0x01, 0x02, 0x00, 0x01, // Request ID
241            0x01, // Protocol Version
242            0x01, // Interface Version
243            0x00, // Message Type
244            0x00, // Return Code
245        ];
246
247        let packet = Packet::new_checked(&raw_packet[..]).unwrap();
248        let repr = Repr::parse(&packet).unwrap();
249
250        assert_eq!(
251            repr,
252            Repr::new(
253                MessageId {
254                    service_id: 0x1234,
255                    method_id: 0x0001,
256                },
257                RequestId {
258                    client_id: ClientId {
259                        client_id_prefix: 0x01,
260                        client_id: 0x02,
261                    },
262                    session_id: 0x0001,
263                },
264                0x01,
265                0x01,
266                MessageType::Request,
267                ReturnCode::E_OK,
268                &[],
269            )
270        );
271    }
272
273    #[test]
274    fn test_repr_emit() {
275        let repr = Repr::new(
276            MessageId {
277                service_id: 0x1234,
278                method_id: 0x0001,
279            },
280            RequestId {
281                client_id: ClientId {
282                    client_id_prefix: 0x01,
283                    client_id: 0x02,
284                },
285                session_id: 0x0001,
286            },
287            0x01,
288            0x01,
289            MessageType::Request,
290            ReturnCode::E_OK,
291            &[0xDE, 0xAD, 0xBE, 0xEF],
292        );
293        let mut buffer = [0u8; 20];
294        let mut packet = Packet::new_unchecked(&mut buffer);
295        repr.emit(&mut packet);
296        let expected: [u8; 20] = [
297            0x12, 0x34, 0x00, 0x01, // Message ID
298            0x00, 0x00, 0x00, 0x0C, // Length
299            0x01, 0x02, 0x00, 0x01, // Request ID
300            0x01, // Protocol Version
301            0x01, // Interface Version
302            0x00, // Message Type
303            0x00, // Return Code
304            0xDE, 0xAD, 0xBE, 0xEF, // Payload
305        ];
306        assert_eq!(&buffer, &expected);
307    }
308
309    fn round_trip_test(repr: Repr) {
310        let mut buffer = [0u8; 1024];
311        {
312            let mut packet = Packet::new_unchecked(&mut buffer);
313            repr.emit(&mut packet);
314        }
315        let packet = Packet::new_checked(&buffer).unwrap();
316        let parsed_repr = Repr::parse(&packet).unwrap();
317        assert_eq!(parsed_repr, repr);
318    }
319
320    fn round_trip_test_with_bytes(repr: Repr, expected_bytes: &[u8]) {
321        let mut buffer = [0u8; 1024]; // Use a large enough fixed-size buffer
322        {
323            let mut packet = Packet::new_unchecked(&mut buffer[..expected_bytes.len()]);
324            repr.emit(&mut packet);
325        }
326
327        assert_eq!(&buffer[..expected_bytes.len()], expected_bytes);
328
329        let packet = Packet::new_checked(&buffer[..expected_bytes.len()]).unwrap();
330        let parsed_repr = Repr::parse(&packet).unwrap();
331        assert_eq!(repr, parsed_repr);
332    }
333
334    #[test]
335    fn test_repr_round_trip_request() {
336        let repr = Repr {
337            message_id: MessageId {
338                service_id: 0x1234,
339                method_id: 0x0001,
340            },
341            length: 12,
342            request_id: RequestId {
343                client_id: ClientId {
344                    client_id_prefix: 0x01,
345                    client_id: 0x02,
346                },
347                session_id: 0x0001,
348            },
349            protocol_version: 0x01,
350            interface_version: 0x01,
351            message_type: MessageType::Request,
352            return_code: ReturnCode::E_OK,
353            data: &[0xDE, 0xAD, 0xBE, 0xEF],
354        };
355        round_trip_test(repr);
356        round_trip_test_with_bytes(
357            repr,
358            &[
359                0x12, 0x34, // Service ID
360                0x00, 0x01, // Method ID
361                0x00, 0x00, 0x00, 0x0C, // Length
362                0x01, 0x02, 0x00, 0x01, // Request ID
363                0x01, // Protocol version
364                0x01, // Interface version
365                0x00, // MessageType
366                0x00, // ReturnCode
367                0xDE, 0xAD, 0xBE, 0xEF, // Data
368            ],
369        );
370    }
371
372    #[test]
373    fn test_repr_round_trip_request_no_return() {
374        let repr = Repr {
375            message_id: MessageId {
376                service_id: 0x1234,
377                method_id: 0x0001,
378            },
379            length: 10,
380            request_id: RequestId {
381                client_id: ClientId {
382                    client_id_prefix: 0x01,
383                    client_id: 0x02,
384                },
385                session_id: 0x0001,
386            },
387            protocol_version: 0x01,
388            interface_version: 0x01,
389            message_type: MessageType::RequestNoReturn,
390            return_code: ReturnCode::E_OK,
391            data: &[0xAA, 0xBB],
392        };
393        round_trip_test(repr);
394    }
395
396    #[test]
397    fn test_repr_round_trip_notification() {
398        let repr = Repr {
399            message_id: MessageId {
400                service_id: 0x5678,
401                method_id: 0x8001,
402            },
403            length: 0,
404            request_id: RequestId {
405                client_id: ClientId {
406                    client_id_prefix: 0xFF,
407                    client_id: 0xFF,
408                },
409                session_id: 0x0001,
410            },
411            protocol_version: 0x01,
412            interface_version: 0x01,
413            message_type: MessageType::Notification,
414            return_code: ReturnCode::E_OK,
415            data: &[],
416        };
417        round_trip_test(repr);
418    }
419
420    #[test]
421    fn test_repr_round_trip_response() {
422        let repr = Repr {
423            message_id: MessageId {
424                service_id: 0x1234,
425                method_id: 0x0001,
426            },
427            length: 16,
428            request_id: RequestId {
429                client_id: ClientId {
430                    client_id_prefix: 0x01,
431                    client_id: 0x02,
432                },
433                session_id: 0x0001,
434            },
435            protocol_version: 0x01,
436            interface_version: 0x01,
437            message_type: MessageType::Response,
438            return_code: ReturnCode::E_OK,
439            data: &[0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77],
440        };
441        round_trip_test(repr);
442    }
443
444    #[test]
445    fn test_repr_round_trip_error() {
446        let repr = Repr {
447            message_id: MessageId {
448                service_id: 0x1234,
449                method_id: 0x0001,
450            },
451            length: 0,
452            request_id: RequestId {
453                client_id: ClientId {
454                    client_id_prefix: 0x01,
455                    client_id: 0x02,
456                },
457                session_id: 0x0001,
458            },
459            protocol_version: 0x01,
460            interface_version: 0x01,
461            message_type: MessageType::Error,
462            return_code: ReturnCode::E_NOT_OK,
463            data: &[],
464        };
465        round_trip_test(repr);
466    }
467
468    #[test]
469    fn test_repr_round_trip_tp_request() {
470        let repr = Repr {
471            message_id: MessageId {
472                service_id: 0xABCD,
473                method_id: 0x0042,
474            },
475            length: 9, 
476            request_id: RequestId {
477                client_id: ClientId {
478                    client_id_prefix: 0x10,
479                    client_id: 0x20,
480                },
481                session_id: 0x1234,
482            },
483            protocol_version: 0x01,
484            interface_version: 0x02,
485            message_type: MessageType::TPRequest,
486            return_code: ReturnCode::E_OK,
487            data: &[0xFF],
488        };
489        round_trip_test(repr);
490    }
491
492    #[test]
493    fn test_repr_round_trip_tp_request_no_return() {
494        let repr = Repr {
495            message_id: MessageId {
496                service_id: 0x0001,
497                method_id: 0x0002,
498            },
499            length: 11, 
500            request_id: RequestId {
501                client_id: ClientId {
502                    client_id_prefix: 0x00,
503                    client_id: 0x01,
504                },
505                session_id: 0x0002,
506            },
507            protocol_version: 0x01,
508            interface_version: 0x01,
509            message_type: MessageType::TPRequestNoReturn,
510            return_code: ReturnCode::E_OK,
511            data: &[0x01, 0x02, 0x03],
512        };
513        round_trip_test(repr);
514    }
515
516    #[test]
517    fn test_repr_round_trip_tp_notification() {
518        let repr = Repr {
519            message_id: MessageId {
520                service_id: 0x9999,
521                method_id: 0x8888,
522            },
523            length: 10, 
524            request_id: RequestId {
525                client_id: ClientId {
526                    client_id_prefix: 0x00,
527                    client_id: 0x00,
528                },
529                session_id: 0x0000,
530            },
531            protocol_version: 0x01,
532            interface_version: 0x01,
533            message_type: MessageType::TPNotification,
534            return_code: ReturnCode::E_OK,
535            data: &[0xCA, 0xFE],
536        };
537        round_trip_test(repr);
538    }
539
540    #[test]
541    fn test_repr_round_trip_tp_response() {
542        let repr = Repr {
543            message_id: MessageId {
544                service_id: 0x4321,
545                method_id: 0x8765,
546            },
547            length: 13,
548            request_id: RequestId {
549                client_id: ClientId {
550                    client_id_prefix: 0xAA,
551                    client_id: 0xBB,
552                },
553                session_id: 0xCCDD,
554            },
555            protocol_version: 0x01,
556            interface_version: 0x05,
557            message_type: MessageType::TPResponse,
558            return_code: ReturnCode::E_OK,
559            data: &[0x10, 0x20, 0x30, 0x40, 0x50],
560        };
561        round_trip_test(repr);
562    }
563
564    #[test]
565    fn test_repr_round_trip_tp_error() {
566        let repr = Repr {
567            message_id: MessageId {
568                service_id: 0xFFFF,
569                method_id: 0xFFFF,
570            },
571            length: 0,
572            request_id: RequestId {
573                client_id: ClientId {
574                    client_id_prefix: 0xFF,
575                    client_id: 0xFE,
576                },
577                session_id: 0xFFFE,
578            },
579            protocol_version: 0x01,
580            interface_version: 0x01,
581            message_type: MessageType::TPError,
582            return_code: ReturnCode::E_TIMEOUT,
583            data: &[],
584        };
585        round_trip_test(repr);
586    }
587
588    // Return code tests
589    #[test]
590    fn test_repr_round_trip_unknown_service() {
591        let repr = Repr {
592            message_id: MessageId {
593                service_id: 0x1234,
594                method_id: 0x0001,
595            },
596            length: 0,
597            request_id: RequestId {
598                client_id: ClientId {
599                    client_id_prefix: 0x01,
600                    client_id: 0x02,
601                },
602                session_id: 0x0001,
603            },
604            protocol_version: 0x01,
605            interface_version: 0x01,
606            message_type: MessageType::Error,
607            return_code: ReturnCode::E_UNKNOWN_SERVICE,
608            data: &[],
609        };
610        round_trip_test(repr);
611    }
612
613    #[test]
614    fn test_repr_round_trip_unknown_method() {
615        let repr = Repr {
616            message_id: MessageId {
617                service_id: 0x1234,
618                method_id: 0x9999,
619            },
620            length: 0,
621            request_id: RequestId {
622                client_id: ClientId {
623                    client_id_prefix: 0x01,
624                    client_id: 0x02,
625                },
626                session_id: 0x0001,
627            },
628            protocol_version: 0x01,
629            interface_version: 0x01,
630            message_type: MessageType::Error,
631            return_code: ReturnCode::E_UNKNOWN_METHOD,
632            data: &[],
633        };
634        round_trip_test(repr);
635    }
636
637    #[test]
638    fn test_repr_round_trip_not_ready() {
639        let repr = Repr {
640            message_id: MessageId {
641                service_id: 0x1234,
642                method_id: 0x0001,
643            },
644            length: 0,
645            request_id: RequestId {
646                client_id: ClientId {
647                    client_id_prefix: 0x01,
648                    client_id: 0x02,
649                },
650                session_id: 0x0001,
651            },
652            protocol_version: 0x01,
653            interface_version: 0x01,
654            message_type: MessageType::Error,
655            return_code: ReturnCode::E_NOT_READY,
656            data: &[],
657        };
658        round_trip_test(repr);
659    }
660
661    #[test]
662    fn test_repr_round_trip_wrong_protocol_version() {
663        let repr = Repr {
664            message_id: MessageId {
665                service_id: 0x1234,
666                method_id: 0x0001,
667            },
668            length: 0,
669            request_id: RequestId {
670                client_id: ClientId {
671                    client_id_prefix: 0x01,
672                    client_id: 0x02,
673                },
674                session_id: 0x0001,
675            },
676            protocol_version: 0x01,
677            interface_version: 0x01,
678            message_type: MessageType::Error,
679            return_code: ReturnCode::E_WRONG_PROTOCOL_VERSION,
680            data: &[],
681        };
682        round_trip_test(repr);
683    }
684
685    #[test]
686    fn test_repr_round_trip_wrong_interface_version() {
687        let repr = Repr {
688            message_id: MessageId {
689                service_id: 0x1234,
690                method_id: 0x0001,
691            },
692            length: 0,
693            request_id: RequestId {
694                client_id: ClientId {
695                    client_id_prefix: 0x01,
696                    client_id: 0x02,
697                },
698                session_id: 0x0001,
699            },
700            protocol_version: 0x01,
701            interface_version: 0x01,
702            message_type: MessageType::Error,
703            return_code: ReturnCode::E_WRONG_INTERFACE_VERSION,
704            data: &[],
705        };
706        round_trip_test(repr);
707    }
708
709    #[test]
710    fn test_repr_round_trip_malformed_message() {
711        let repr = Repr {
712            message_id: MessageId {
713                service_id: 0x1234,
714                method_id: 0x0001,
715            },
716            length: 0,
717            request_id: RequestId {
718                client_id: ClientId {
719                    client_id_prefix: 0x01,
720                    client_id: 0x02,
721                },
722                session_id: 0x0001,
723            },
724            protocol_version: 0x01,
725            interface_version: 0x01,
726            message_type: MessageType::Error,
727            return_code: ReturnCode::E_MALFORMED_MESSAGE,
728            data: &[],
729        };
730        round_trip_test(repr);
731    }
732
733    #[test]
734    fn test_repr_round_trip_wrong_message_type() {
735        let repr = Repr {
736            message_id: MessageId {
737                service_id: 0x1234,
738                method_id: 0x0001,
739            },
740            length: 0,
741            request_id: RequestId {
742                client_id: ClientId {
743                    client_id_prefix: 0x01,
744                    client_id: 0x02,
745                },
746                session_id: 0x0001,
747            },
748            protocol_version: 0x01,
749            interface_version: 0x01,
750            message_type: MessageType::Error,
751            return_code: ReturnCode::E_WRONG_MESSAGE_TYPE,
752            data: &[],
753        };
754        round_trip_test(repr);
755    }
756
757    #[test]
758    fn test_repr_round_trip_e2e_errors() {
759        // Test E2E_REPEATED
760        let repr = Repr {
761            message_id: MessageId {
762                service_id: 0x1234,
763                method_id: 0x0001,
764            },
765            length: 0,
766            request_id: RequestId {
767                client_id: ClientId {
768                    client_id_prefix: 0x01,
769                    client_id: 0x02,
770                },
771                session_id: 0x0001,
772            },
773            protocol_version: 0x01,
774            interface_version: 0x01,
775            message_type: MessageType::Error,
776            return_code: ReturnCode::E_E2E_REPEATED,
777            data: &[],
778        };
779        round_trip_test(repr);
780
781        // Test E2E_WRONG_SEQUENCE
782        let repr = Repr {
783            return_code: ReturnCode::E_E2E_WRONG_SEQUENCE,
784            ..repr
785        };
786        round_trip_test(repr);
787
788        // Test E2E
789        let repr = Repr {
790            return_code: ReturnCode::E_E2E,
791            ..repr
792        };
793        round_trip_test(repr);
794
795        // Test E2E_NOT_AVAILABLE
796        let repr = Repr {
797            return_code: ReturnCode::E_E2E_NOT_AVAILABLE,
798            ..repr
799        };
800        round_trip_test(repr);
801
802        // Test E2E_NO_NEW_DATA
803        let repr = Repr {
804            return_code: ReturnCode::E_E2E_NO_NEW_DATA,
805            ..repr
806        };
807        round_trip_test(repr);
808    }
809
810    #[test]
811    fn test_repr_round_trip_reserved_someip_error() {
812        // Test reserved SOME/IP error range (0x10-0x1F)
813        let repr = Repr {
814            message_id: MessageId {
815                service_id: 0x1234,
816                method_id: 0x0001,
817            },
818            length: 0,
819            request_id: RequestId {
820                client_id: ClientId {
821                    client_id_prefix: 0x01,
822                    client_id: 0x02,
823                },
824                session_id: 0x0001,
825            },
826            protocol_version: 0x01,
827            interface_version: 0x01,
828            message_type: MessageType::Error,
829            return_code: ReturnCode::from_u8(0x10).unwrap(),
830            data: &[],
831        };
832        round_trip_test(repr);
833
834        let repr = Repr {
835            return_code: ReturnCode::from_u8(0x1F).unwrap(),
836            ..repr
837        };
838        round_trip_test(repr);
839    }
840
841    #[test]
842    fn test_repr_round_trip_service_method_error() {
843        // Test service/method specific error range (0x20-0x5E)
844        let repr = Repr {
845            message_id: MessageId {
846                service_id: 0x1234,
847                method_id: 0x0001,
848            },
849            length: 0,
850            request_id: RequestId {
851                client_id: ClientId {
852                    client_id_prefix: 0x01,
853                    client_id: 0x02,
854                },
855                session_id: 0x0001,
856            },
857            protocol_version: 0x01,
858            interface_version: 0x01,
859            message_type: MessageType::Error,
860            return_code: ReturnCode::from_u8(0x20).unwrap(),
861            data: &[],
862        };
863        round_trip_test(repr);
864
865        let repr = Repr {
866            return_code: ReturnCode::from_u8(0x42).unwrap(),
867            ..repr
868        };
869        round_trip_test(repr);
870
871        let repr = Repr {
872            return_code: ReturnCode::from_u8(0x5E).unwrap(),
873            ..repr
874        };
875        round_trip_test(repr);
876    }
877
878    #[test]
879    fn test_return_code_public_api() {
880        // Test named variants
881        let ok = ReturnCode::E_OK;
882        assert!(ok.is_ok());
883        assert!(!ok.is_reserved_someip());
884        assert!(!ok.is_reserved_service_method());
885        assert_eq!(ok.as_u8(), 0x00);
886
887        // Test reserved SOME/IP range
888        let reserved_someip = ReturnCode::ReservedSomeIP(0x15);
889        assert!(!reserved_someip.is_ok());
890        assert!(reserved_someip.is_reserved_someip());
891        assert!(!reserved_someip.is_reserved_service_method());
892        assert_eq!(reserved_someip.as_u8(), 0x15);
893
894        // Test reserved service/method range
895        let reserved_service = ReturnCode::ReservedServiceMethod(0x42);
896        assert!(!reserved_service.is_ok());
897        assert!(!reserved_service.is_reserved_someip());
898        assert!(reserved_service.is_reserved_service_method());
899        assert_eq!(reserved_service.as_u8(), 0x42);
900
901        // Test pattern matching
902        match ReturnCode::from_u8(0x10).unwrap() {
903            ReturnCode::ReservedSomeIP(code) => assert_eq!(code, 0x10),
904            _ => panic!("Expected ReservedSomeIP variant"),
905        }
906
907        match ReturnCode::from_u8(0x20).unwrap() {
908            ReturnCode::ReservedServiceMethod(code) => assert_eq!(code, 0x20),
909            _ => panic!("Expected ReservedServiceMethod variant"),
910        }
911
912        // Test conversions - Display trait exists but we're in no_std so skip format! tests
913        // The Display impl is tested implicitly when used with Repr
914    }
915}