Skip to content

fix(derive): make example doctests actually compile#41

Closed
JustinKovacich wants to merge 1 commit into
mainfrom
fix/derive_doctests_ignore
Closed

fix(derive): make example doctests actually compile#41
JustinKovacich wants to merge 1 commit into
mainfrom
fix/derive_doctests_ignore

Conversation

@JustinKovacich
Copy link
Copy Markdown
Contributor

@JustinKovacich JustinKovacich commented May 20, 2026

Summary

The doctests on #[derive(Identifier)] were aspirational pseudocode that documented a contract the macro doesn't actually emit — they had been failing cargo test --doc -p uds_protocol_derive since they were written. The cause was both a missing dev-dependency and several semantic issues in the example code itself.

Fixed inline:

  1. Missing dev-dep. uds_protocol_derive/Cargo.toml had no [dev-dependencies] entry, so use uds_protocol::* failed with unresolved import. Added uds_protocol = { path = ".." }. This forms a logical cycle (the parent already depends on this crate) but cargo permits dev-dep cycles — same pattern serde_derive uses to dev-dep serde.

  2. Identifier macro-namespace collision. The example imported Identifier as both the trait and the derive macro from separate crates, tripping E0252. uds_protocol::Identifier brings both into scope at once (trait + macro live in different namespaces under the same name), so the duplicate use uds_protocol_derive::Identifier was redundant + wrong.

  3. Serialize derive without the impl. The enum example used Serialize in its derive list but UDSRoutineIdentifier doesn't implement Serialize. Dropped — the example is about Identifier, not serde.

  4. ? on Infallible Result. UDSRoutineIdentifier::try_from(value)? won't compile because UDSRoutineIdentifier has a total impl From<u16> so its blanket TryFrom returns Result<_, Infallible>. Swapped to the direct ::from(value).

  5. ProtocolIdentifier naming collision. Struct example's name collided with the existing uds_protocol::ProtocolIdentifier re-export. Renamed to WrappedIdentifier + added the matching TryFrom / From for u16 impls 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_derive renders both examples with syntax highlighting and the new contract clarification preceding them
  • Reviewer confirms the rewritten examples accurately describe the intended derive contract — the original snippets implied the macro emits TryFrom / From itself, which it doesn't

Discovered downstream of dft.git while running pre-existing test triage; no functional change to the macro implementation.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings May 20, 2026 16:06
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ignore so cargo test --doc -p uds_protocol_derive no 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/qualifying Serialize (and uds_protocol doesn’t appear to re-export it). Even though the doctest is now ignored, consider removing Serialize from the example or using serde::Serialize / use serde::Serialize (possibly behind the crate’s serde feature) 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/qualifying Serialize, so it won’t compile if copied as-is. Consider dropping Serialize from the example or changing it to serde::Serialize / adding use serde::Serialize (potentially gated on the serde feature) 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>
@JustinKovacich JustinKovacich force-pushed the fix/derive_doctests_ignore branch from 25bbb7f to 5212a48 Compare May 20, 2026 16:18
@JustinKovacich JustinKovacich changed the title fix(derive): mark doctests ignore to break cyclic-dep build fix(derive): make example doctests actually compile May 20, 2026
@JustinKovacich
Copy link
Copy Markdown
Contributor Author

Closing — this PR is obsolete. While I was rebuilding the fix, I noticed that origin/main has already deleted the entire uds_protocol_derive crate directory (commit a7c650c) and replaced it with a macro_rules! implementation inside uds_protocol itself (d41299c), shipped as part of #40. The doctest failures I was chasing only exist in dft.git's pinned submodule revision (e5dac09), which predates that refactor. Real fix on the dft side is bumping the submodule pin past 560ff94 to pick up the macro_rules refactor + the non_exhaustive enum hardening that landed alongside it. Apologies for the noise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants