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}