veecle_os_data_support_someip_macros/lib.rs
1//! This crate provides SOME/IP macros.
2
3use proc_macro::TokenStream;
4use syn::{DeriveInput, parse_macro_input};
5
6mod parse;
7mod serialize;
8
9/// Derives implementation of the `Parse` trait.
10///
11/// ```rust
12/// use veecle_os_data_support_someip::parse::{Parse, ParseExt};
13///
14/// #[derive(Debug, PartialEq, Parse)]
15/// struct SomeIpStruct {
16/// foo: u16,
17/// bar: u32,
18/// }
19///
20/// let bytes = &[0x0, 0x6, 0x1, 0x2, 0x3, 0x4];
21/// let deserialized = SomeIpStruct {
22/// foo: 6,
23/// bar: 0x1020304,
24/// };
25///
26/// let my_struct = SomeIpStruct::parse(bytes).unwrap();
27/// assert_eq!(my_struct, deserialized);
28/// ```
29///
30/// It can also derive implementations for structs with a single lifetime parameter:
31///
32/// ```rust
33/// use veecle_os_data_support_someip::parse::{ByteReader, Parse, ParseError, ParseExt};
34///
35/// #[derive(Debug)]
36/// struct Foo;
37///
38/// impl<'a> Parse<'a> for &'a Foo {
39/// fn parse_partial(reader: &mut ByteReader<'a>) -> Result<Self, ParseError> {
40/// Ok(&Foo)
41/// }
42/// }
43///
44/// #[derive(Debug, Parse)]
45/// struct WithLifetimeDerived<'foo> {
46/// inner: &'foo Foo,
47/// }
48///
49/// assert!(WithLifetimeDerived::parse(&[]).is_ok());
50/// ```
51///
52/// Zero sized types and tuple structs can be derived as well.
53///
54/// ```rust
55/// use veecle_os_data_support_someip::parse::Parse;
56///
57/// #[derive(Parse)]
58/// struct Zst;
59///
60/// #[derive(Parse)]
61/// struct TupleStruct(u32, u16);
62/// ```
63///
64/// It cannot be derived for enums, unions, or structs with more than one lifetime.
65///
66/// ```compile_fail
67/// use veecle_os_data_support_someip::parse::{Parse};
68///
69/// #[derive(Parse)]
70/// enum Bad {}
71///
72/// #[derive(Parse)]
73/// union AlsoBad {
74/// foo: u8,
75/// bar: u8,
76/// }
77///
78/// #[derive(Parse)]
79/// struct Lively<'a, 'b> {
80/// foo: PhantomData<(&'a (), &'b ())>,
81/// }
82/// ```
83#[proc_macro_derive(Parse)]
84pub fn someip_parse(input: TokenStream) -> TokenStream {
85 let derive_input = parse_macro_input!(input as DeriveInput);
86 parse::impl_derive_parse(derive_input).unwrap_or_else(|error| error.into_compile_error().into())
87}
88
89/// Derives implementation of the `Serialize` trait.
90///
91/// ```rust
92/// use veecle_os_data_support_someip::serialize::{Serialize, SerializeExt};
93///
94/// #[derive(Debug, PartialEq, Serialize)]
95/// struct SomeIpStruct {
96/// foo: u16,
97/// bar: u32,
98/// }
99///
100/// let input = SomeIpStruct {
101/// foo: 6,
102/// bar: 0x1020304,
103/// };
104/// let bytes = &[0x0, 0x6, 0x1, 0x2, 0x3, 0x4];
105///
106/// let mut buffer = [0u8; 16];
107/// let output = input.serialize(&mut buffer).unwrap();
108///
109/// assert_eq!(output, bytes);
110/// ```
111///
112/// Zero sized types and tuple structs can be derived as well.
113///
114/// ```rust
115/// use veecle_os_data_support_someip::serialize::Serialize;
116///
117/// #[derive(Serialize)]
118/// struct Zst;
119///
120/// #[derive(Serialize)]
121/// struct TupleStruct(u32, u16);
122/// ```
123///
124/// It cannot be derived for enums or unions.
125///
126/// ```compile_fail
127/// use veecle_os_data_support_someip::serialize::{Serialize};
128///
129/// #[derive(Serialize)]
130/// enum Bad {}
131///
132/// #[derive(Serialize)]
133/// union AlsoBad {
134/// foo: u8,
135/// bar: u8,
136/// }
137/// ```
138#[proc_macro_derive(Serialize)]
139pub fn someip_serialize(input: TokenStream) -> TokenStream {
140 let derive_input = parse_macro_input!(input as DeriveInput);
141 serialize::impl_derive_serialize(derive_input)
142 .unwrap_or_else(|error| error.into_compile_error().into())
143}
144
145/// Returns a path to the `veecle_os_data_support_someip` crate.
146fn veecle_os_data_support_someip_path() -> syn::Result<syn::Path> {
147 proc_macro_crate::crate_name("veecle-os-data-support-someip")
148 .map(|found| match found {
149 proc_macro_crate::FoundCrate::Itself => {
150 syn::parse_quote!(::veecle_os_data_support_someip)
151 }
152 proc_macro_crate::FoundCrate::Name(name) => {
153 let ident = syn::Ident::new(&name, proc_macro2::Span::call_site());
154 syn::parse_quote!(::#ident)
155 }
156 })
157 .or_else(|_| {
158 proc_macro_crate::crate_name("veecle-os").map(|found| match found {
159 proc_macro_crate::FoundCrate::Itself => {
160 todo!("unused currently, not sure what behavior will be wanted")
161 }
162 proc_macro_crate::FoundCrate::Name(name) => {
163 let ident = syn::Ident::new(&name, proc_macro2::Span::call_site());
164 syn::parse_quote!(::#ident::data_support::someip)
165 }
166 })
167 })
168 .map_err(|_| {
169 syn::Error::new(
170 proc_macro2::Span::call_site(),
171 "could not find either veecle-os-data-support-someip or veecle-os crates",
172 )
173 })
174}