fix(derive): make example doctests actually compile#41
Conversation
There was a problem hiding this comment.
Pull request overview
Updates the rustdoc examples in uds_protocol_derive to avoid failing doctests caused by a dependency-cycle (examples referencing uds_protocol, which depends on uds_protocol_derive).
Changes:
- Marked the two rustdoc code fences as
ignoresocargo test --doc -p uds_protocol_deriveno longer fails. - Added short inline explanations above each snippet describing the cyclic-dependency constraint.
- Minor punctuation tweak in the struct example description.
Comments suppressed due to low confidence (2)
uds_protocol_derive/src/lib.rs:18
- The example code inside this fenced block uses
#[derive(..., Serialize)]without importing/qualifyingSerialize(anduds_protocoldoesn’t appear to re-export it). Even though the doctest is now ignored, consider removingSerializefrom the example or usingserde::Serialize/use serde::Serialize(possibly behind the crate’sserdefeature) to keep the docs copy-pastable.
/// ```ignore
/// use uds_protocol::{UDSRoutineIdentifier, Identifier, Error};
///
/// #[derive(Clone, Copy, Identifier, Serialize)]
/// pub enum MyRoutineIdentifier {
uds_protocol_derive/src/lib.rs:53
- This snippet includes
#[derive(..., Serialize)]without importing/qualifyingSerialize, so it won’t compile if copied as-is. Consider droppingSerializefrom the example or changing it toserde::Serialize/ addinguse serde::Serialize(potentially gated on theserdefeature) so the documentation remains self-contained.
/// ```ignore
/// use uds_protocol::{UDSIdentifier, Identifier};
///
/// #[derive(Clone, Copy, Identifier, Serialize)]
/// pub struct ProtocolIdentifier {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The doctests on `Identifier`-derive were aspirational pseudocode — they imported types from `uds_protocol`, but `uds_protocol_derive` had no `[dev-dependencies]` entry at all, so the snippets failed their `cargo test --doc` run with "unresolved import `uds_protocol`". Fixing the imports also surfaced several semantic issues in the example code itself: 1. The example imported `Identifier` as both the trait (from `uds_protocol::traits`) and the derive macro (re-exported from `uds_protocol_derive`), tripping E0252 on the macro-namespace collision. `uds_protocol::Identifier` brings both into scope at once (trait in type namespace, macro in macro namespace) — drop the duplicate `use uds_protocol_derive::Identifier`. 2. The enum example used `Serialize` in its `#[derive(...)]` list but `UDSRoutineIdentifier` doesn't implement `Serialize`, so the wrapping `derive` failed. Dropped — the example is about `Identifier`, not serde, and the serde gating was incidental noise. 3. The fallthrough arm used `UDSRoutineIdentifier::try_from(value)?`, but `UDSRoutineIdentifier` has a *total* `impl From<u16>` (every u16 maps to one of its variants, including reserved ranges) — so `try_from` returns `Result<_, Infallible>` and the `?` couldn't convert to `Error`. Swapped to the infallible `::from(value)`. 4. The struct example previously named the type `ProtocolIdentifier`, which collides with the existing `uds_protocol::ProtocolIdentifier` re-export at `lib.rs:13`. Renamed to `WrappedIdentifier` to avoid shadowing in the doctest namespace, and added the matching `TryFrom<u16>` / `From<_> for u16` impls that the enum example demonstrates — keeping the illustrative pattern intact across both examples. Added `[dev-dependencies]` entry pointing back at `uds_protocol`. This forms a logical cycle (the crate `uds_protocol` already depends on `uds_protocol_derive`), but cargo permits dev-dep cycles because dev-deps are only resolved when building *this* crate's tests, not when something else consumes the proc-macro. Same pattern `serde_derive` uses to dev-dep `serde`. Local: `cargo test --doc -p uds_protocol_derive` → 2 passed, was 2 failed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
25bbb7f to
5212a48
Compare
|
Closing — this PR is obsolete. While I was rebuilding the fix, I noticed that origin/main has already deleted the entire |
Summary
The doctests on
#[derive(Identifier)]were aspirational pseudocode that documented a contract the macro doesn't actually emit — they had been failingcargo test --doc -p uds_protocol_derivesince they were written. The cause was both a missing dev-dependency and several semantic issues in the example code itself.Fixed inline:
Missing dev-dep.
uds_protocol_derive/Cargo.tomlhad no[dev-dependencies]entry, souse uds_protocol::*failed withunresolved import. Addeduds_protocol = { path = ".." }. This forms a logical cycle (the parent already depends on this crate) but cargo permits dev-dep cycles — same patternserde_deriveuses to dev-depserde.Identifiermacro-namespace collision. The example importedIdentifieras both the trait and the derive macro from separate crates, tripping E0252.uds_protocol::Identifierbrings both into scope at once (trait + macro live in different namespaces under the same name), so the duplicateuse uds_protocol_derive::Identifierwas redundant + wrong.Serializederive without the impl. The enum example usedSerializein its derive list butUDSRoutineIdentifierdoesn't implementSerialize. Dropped — the example is aboutIdentifier, not serde.?on Infallible Result.UDSRoutineIdentifier::try_from(value)?won't compile becauseUDSRoutineIdentifierhas a totalimpl From<u16>so its blanketTryFromreturnsResult<_, Infallible>. Swapped to the direct::from(value).ProtocolIdentifiernaming collision. Struct example's name collided with the existinguds_protocol::ProtocolIdentifierre-export. Renamed toWrappedIdentifier+ added the matchingTryFrom/From for u16impls so both examples illustrate the same hand-written-conversion pattern.The derive itself emits
impl Identifier for #name {}only — callers supply their own wire-format conversions. The examples now show that pattern faithfully.Test plan
cargo test --doc -p uds_protocol_derive→ 2 passed, 0 failed (was 0 passed, 2 failed)cargo doc -p uds_protocol_deriverenders both examples with syntax highlighting and the new contract clarification preceding themTryFrom/Fromitself, which it doesn'tDiscovered downstream of dft.git while running pre-existing test triage; no functional change to the macro implementation.
🤖 Generated with Claude Code