someip_sd_wire/lib.rs
1#![cfg_attr(not(test), no_std)]
2#![warn(missing_docs)]
3
4//! # SOME/IP-SD-wire
5//!
6//! This crate provides the means for parsing byte arrays into higher-level
7//! SOME/IP Service Discovery representations, and vice versa. It is designed to be used in embedded
8//! environments and is a `no_std` crate by default.
9//!
10//! ## Features
11//!
12//! - `no_std` compatible by default
13//! - Zero-allocation parsing and serialization
14//! - Support for all SOME/IP-SD message types
15//! - Clean enum-based API for entry and option types
16//! - Wire format using smoltcp-inspired zero-copy pattern
17//!
18//! ## Architecture
19//!
20//! Following the smoltcp/someip-wire pattern:
21//! - `packet` - Zero-copy wrapper around raw packet buffers
22//! - `repr` - High-level representation for parsing/emitting
23//! - `entries` - Zero-copy wrappers for service/eventgroup entries
24//! - `options` - Zero-copy wrappers for various option types
25//! - `config` - DNS-SD TXT record configuration options
26//! - `field` - Field offset definitions
27
28/// DNS-SD TXT record style configuration options for SOME/IP-SD.
29pub mod config;
30
31/// Service and EventGroup entry types with zero-copy wrappers.
32pub mod entries;
33
34/// Error type for parsing and validation failures.
35pub mod error;
36
37/// Field offset definitions for all wire format structures.
38pub mod field;
39
40/// SOME/IP-SD option types (IPv4/IPv6 Endpoint, LoadBalancing, etc.).
41pub mod options;
42
43/// Zero-copy packet wrapper for SOME/IP-SD messages.
44pub mod packet;
45
46/// High-level representation for parse/emit operations.
47pub mod repr;
48
49/// Prelude module for convenient imports.
50pub mod prelude;
51
52#[cfg(test)]
53mod zero_cost_tests {
54 use super::*;
55
56 /// Verify that Packet and Repr are zero-sized wrappers (zero-cost abstraction)
57 /// The Packet struct should only contain a reference/slice to the buffer, no additional overhead
58 #[test]
59 fn test_zero_cost_packet_wrapper() {
60 use core::mem::size_of;
61
62 // Packet<&[u8]> should be same size as a slice reference (2 * usize: ptr + len)
63 assert_eq!(size_of::<packet::Packet<&[u8]>>(), size_of::<&[u8]>());
64
65 // Packet<&mut [u8]> should be same size as a mutable slice reference
66 assert_eq!(size_of::<packet::Packet<&mut [u8]>>(), size_of::<&mut [u8]>());
67 }
68
69 /// Verify that Repr doesn't add overhead beyond its slice references
70 #[test]
71 fn test_zero_cost_repr() {
72 use core::mem::size_of;
73
74 // Repr should be: u8 + u32 + 2 slices = 1 + 4 + 2*(ptr+len) + padding
75 // On 32-bit: ~20-24 bytes, on 64-bit: ~40-48 bytes
76 // The important part is it's just the fields, no heap pointers
77 let repr_size = size_of::<repr::Repr>();
78 let expected_min = size_of::<u8>() + size_of::<u32>() + 2 * size_of::<&[u8]>();
79
80 assert!(repr_size >= expected_min);
81 assert!(repr_size <= expected_min + 16); // Allow for alignment padding
82 }
83
84 /// Verify operations are const/inline-friendly (compile-time test)
85 /// This tests that field range calculations can be used in const contexts
86 #[test]
87 fn test_const_field_calculations() {
88 const _ENTRIES_LEN_END: usize = field::entries::LENGTH.end;
89 const _MIN_HEADER: usize = field::entries::MIN_HEADER_LEN;
90
91 // If this compiles, the calculations are const-evaluable (zero-cost)
92 assert_eq!(_MIN_HEADER, 8);
93 assert_eq!(_ENTRIES_LEN_END, 8);
94 }
95
96 /// Verify that parse/emit operations work on stack-allocated buffers
97 /// This demonstrates the intended usage pattern: all data lives on the stack or in user-provided buffers
98 #[test]
99 fn test_stack_only_operations() {
100 let mut buffer = [0u8; 64];
101
102 // Setup a minimal valid packet on the stack
103 buffer[0] = 0x80; // flags
104 // reserved: 0, 0, 0
105 // entries_length: 0, 0, 0, 0
106 // options_length: 0, 0, 0, 0
107
108 // All operations borrow from user-provided buffers (zero-copy)
109 let packet = packet::Packet::new_checked(&buffer[..]).unwrap();
110 let repr = repr::Repr::parse(&packet).unwrap();
111
112 // Emit to another user-provided buffer (zero-copy)
113 let mut out_buffer = [0u8; 64];
114 let mut out_packet = packet::Packet::new_unchecked(&mut out_buffer[..]);
115 repr.emit(&mut out_packet);
116
117 assert_eq!(out_packet.flags(), 0x80);
118 }
119}
120
121// Compile-time assertion that we don't link against an allocator in no_std mode
122// This will fail to compile if somehow an allocator is required
123#[cfg(not(test))]
124unsafe extern "C" {
125 // This symbol should NOT exist - if it's required, compilation will fail with "undefined reference"
126 // Remove this if you ever need to add allocation support
127 #[link_name = "\n\nERROR: This crate must not require an allocator\n\n"]
128 fn __rust_alloc_trigger_compile_error() -> !;
129}