About rust-trait-api-design
A skill for Rust developers designing trait-based APIs. It helps decide when to use concrete types, generics, or trait objects, with guidance on bounds, conversions, object safety, and API tests.
Key features
- 01Choose concrete, generic, or dynamic dispatch
- 02Place bounds where needed
- 03Design downstream implementation boundaries
- 04Use standard conversion traits
- 05Review trait object safety
- 06Test public API usage
Use cases
- 01Designing a public Rust trait API
- 02Choosing generics or dyn Trait
- 03Reviewing conversion implementations
- 04Testing API calls for downstream users
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ lvtd-llc/ skills --skill rust-trait-api-designAfter installing, type/rust-trait-api-designin Claude Code to confirm it loaded.
Bundled filesagents/openai.yamlreferences/trait-api-patterns.md
Details
From the project READMERust Trait API Design
Use this skill to make Rust APIs generic where useful, concrete where simpler, and object-safe when dynamic dispatch is part of the design. Optimize for the smallest capability contract that callers and implementors can understand.
Core Workflow
- Identify whether the API consumes, borrows, returns, stores, or dispatches behavior.
- Start with concrete types for local code. Generalize only when at least two callers or implementations need the flexibility.
- Use generic bounds for compile-time polymorphism and inlining. Use
dyn Traitfor heterogeneous values, plugin-like extension points, or runtime dispatch. - Place bounds at the point that needs them. Prefer
whereclauses when bounds are long or involve associated types. - Decide whether a trait is intended for downstream implementation. Seal it, keep fields private, or use constructors when invariants must not be implemented externally.
- Use standard conversion traits where they match exactly. Do not invent a
custom conversion trait before checking
From,TryFrom,AsRef,AsMut,Borrow,ToOwned, andCow. - Add compile tests, unit tests, or examples that prove the public API is callable the way the skill expects future users to call it.
API Design Rules
- Accept
impl Traitor a named generic for parameters when callers should pass many concrete types. - Return
impl Traitwhen hiding one concrete return type. ReturnBox<dyn Trait>when the concrete type varies at runtime. - Prefer associated types when each implementation has one natural related type. Prefer generic trait parameters when one implementation supports many target types.
- Implement
Fromfor infallible conversions andTryFromfor fallible conversions. Implementing these gives callersIntoandTryInto. - Use
AsReffor cheap reference-to-reference conversion. UseBorrowonly when borrowed and owned forms have equivalentEq,Hash, andOrdbehavior. - Avoid
Copybounds unless the algorithm semantically requires bitwise copy.
Trait Object Review
Read references/trait-api-patterns.md when choosing between generics and
dyn Trait, or when public traits fail object-safety checks.
Before making a public trait object-safe, check:
- Methods do not use generic type parameters.
- Methods do not return
Selfunless constrained withwhere Self: Sized. - Associated types are specified on the trait object where needed.
- The object is behind a pointer such as
&dyn Trait,Box<dyn Trait>, orArc<dyn Trait + Send + Sync>.
Common Smells
- A public function takes
&Vec<T>because it only needs iteration. - The API accepts
Stringand immediately borrows it as&str. - The API implements
Intodirectly instead ofFrom. - A trait has many blanket bounds that only one method needs.
- A trait object was used because lifetimes were confusing, not because runtime dispatch is required.
async-traitis used in a public trait without checking whether nativeasync fnin traits,trait-variant, or boxed futures fit the dispatch andSendneeds better.