Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions uds_protocol_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,12 @@ proc-macro = true
proc-macro2 = { version="1", features = ["proc-macro"] }
quote = "1"
syn = "2"

# Dev-deps only — used by the doctest examples in `src/lib.rs`. The
# crate is a dependency of `uds_protocol`, so depending back on
# `uds_protocol` here forms a *logical* cycle, but cargo permits this
# because dev-deps are only resolved when building *this crate's own*
# tests, not when something else consumes the proc-macro. Same pattern
# `serde_derive` uses to dev-dep `serde`.
[dev-dependencies]
uds_protocol = { path = ".." }
85 changes: 61 additions & 24 deletions uds_protocol_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,85 @@ use syn::{DeriveInput, parse_macro_input};

/// Derive Identifier and implement `TryFrom<u16>`, `Into<u16>` traits
///
/// The derive itself emits only `impl Identifier for #name {}` — it
/// asserts trait conformance and nothing else. Callers supply their
/// own `TryFrom<u16>` / `From<#name> for u16` so the wire-format
/// dispatch matches the application's own identifier-space layout.
/// The examples below show that hand-written pattern alongside the
/// derive.
///
/// ## Enum Example
///
/// Adds a custom `VerifySignature` routine identifier on top of the
/// standard ISO UDS set via a fallthrough variant. The
/// `UDSRoutineIdentifier` type has a total `From<u16>` (every u16
/// maps to one of its variants, including reserved ranges), so the
/// fallthrough arm uses the infallible `::from` rather than `?`.
///
/// ```rust
/// use uds_protocol::{UDSRoutineIdentifier, Identifier, Error};
/// use uds_protocol::{Error, Identifier, UDSRoutineIdentifier};
///
/// #[derive(Clone, Copy, Identifier, Serialize)]
/// #[derive(Clone, Copy, Identifier)]
/// pub enum MyRoutineIdentifier {
/// /// 0x0101 (example)
/// VerifySignature,
/// /// 0x0101 (example)
/// VerifySignature,
///
/// // Standard ISO UDS routine fallthrough
/// UDSRoutineIdentifier(UDSRoutineIdentifier),
/// /// Standard ISO UDS routine fallthrough.
/// UDSRoutineIdentifier(UDSRoutineIdentifier),
/// }
///
/// impl TryFrom<u16> for MyRoutineIdentifier {
/// type Error = uds_protocol::Error;
/// fn try_from(value: u16) -> Result<Self, Self::Error> {
/// match value {
/// 0x0101 => Ok(MyRoutineIdentifier::VerifySignature),
/// _ => Ok(MyRoutineIdentifier::UDSRoutineIdentifier(UDSRoutineIdentifier::try_from(value)?)),
/// }
/// }
/// type Error = Error;
/// fn try_from(value: u16) -> Result<Self, Self::Error> {
/// match value {
/// 0x0101 => Ok(MyRoutineIdentifier::VerifySignature),
/// // `UDSRoutineIdentifier::from` is total over u16,
/// // so the fallthrough never fails.
/// _ => Ok(MyRoutineIdentifier::UDSRoutineIdentifier(
/// UDSRoutineIdentifier::from(value),
/// )),
/// }
/// }
/// }
///
/// impl From<MyRoutineIdentifier> for u16 {
/// fn from(value: MyRoutineIdentifier) -> Self {
/// match value {
/// MyRoutineIdentifier::VerifySignature => 0x0101,
/// MyRoutineIdentifier::UDSRoutineIdentifier(identifier) => u16::from(identifier),
/// }
/// }
/// fn from(value: MyRoutineIdentifier) -> Self {
/// match value {
/// MyRoutineIdentifier::VerifySignature => 0x0101,
/// MyRoutineIdentifier::UDSRoutineIdentifier(identifier) => u16::from(identifier),
/// }
/// }
/// }
/// ```
///
/// ## Struct definition Example
/// Structs can only contain a single value to be used as an identifier to constrain the type
///
/// Structs can only contain a single value to be used as an identifier
/// to constrain the type. `UDSIdentifier` has a real `TryFrom<u16>`
/// (returning `uds_protocol::Error` for out-of-range values), so the
/// struct wrapper's own `TryFrom` propagates via `?`.
///
/// ```rust
/// use uds_protocol::{Error, Identifier, UDSIdentifier};
///
/// #[derive(Clone, Copy, Identifier)]
/// pub struct WrappedIdentifier {
/// identifier: UDSIdentifier,
/// }
///
/// use uds_protocol::{UDSIdentifier, Identifier};
/// impl TryFrom<u16> for WrappedIdentifier {
/// type Error = Error;
/// fn try_from(value: u16) -> Result<Self, Self::Error> {
/// Ok(WrappedIdentifier {
/// identifier: UDSIdentifier::try_from(value)?,
/// })
/// }
/// }
///
/// #[derive(Clone, Copy, Identifier, Serialize)]
/// pub struct ProtocolIdentifier {
/// identifier: UDSIdentifier,
/// impl From<WrappedIdentifier> for u16 {
/// fn from(value: WrappedIdentifier) -> Self {
/// u16::from(value.identifier)
/// }
/// }
/// ```
///
Expand Down