diff --git a/uds_protocol_derive/Cargo.toml b/uds_protocol_derive/Cargo.toml index cf79e1a..fbdbd2e 100644 --- a/uds_protocol_derive/Cargo.toml +++ b/uds_protocol_derive/Cargo.toml @@ -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 = ".." } diff --git a/uds_protocol_derive/src/lib.rs b/uds_protocol_derive/src/lib.rs index 64d4a94..556eee2 100644 --- a/uds_protocol_derive/src/lib.rs +++ b/uds_protocol_derive/src/lib.rs @@ -6,48 +6,85 @@ use syn::{DeriveInput, parse_macro_input}; /// Derive Identifier and implement `TryFrom`, `Into` traits /// +/// The derive itself emits only `impl Identifier for #name {}` — it +/// asserts trait conformance and nothing else. Callers supply their +/// own `TryFrom` / `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` (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 for MyRoutineIdentifier { -/// type Error = uds_protocol::Error; -/// fn try_from(value: u16) -> Result { -/// match value { -/// 0x0101 => Ok(MyRoutineIdentifier::VerifySignature), -/// _ => Ok(MyRoutineIdentifier::UDSRoutineIdentifier(UDSRoutineIdentifier::try_from(value)?)), -/// } -/// } +/// type Error = Error; +/// fn try_from(value: u16) -> Result { +/// 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 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` +/// (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 for WrappedIdentifier { +/// type Error = Error; +/// fn try_from(value: u16) -> Result { +/// Ok(WrappedIdentifier { +/// identifier: UDSIdentifier::try_from(value)?, +/// }) +/// } +/// } /// -/// #[derive(Clone, Copy, Identifier, Serialize)] -/// pub struct ProtocolIdentifier { -/// identifier: UDSIdentifier, +/// impl From for u16 { +/// fn from(value: WrappedIdentifier) -> Self { +/// u16::from(value.identifier) +/// } /// } /// ``` ///