用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tomevault-io/skills-registry --skill rust-api-design命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
| Use when this capability is needed.
> Use when this capability is needed.
Review architecture and API design for the vfs-s3 project. Use when the user mentions @architect, asks to review an issue's design, discuss module boundaries, API shape, or architectural decisions for vfs-s3. Also trigger when the user wants to create an ADR (Architecture Decision Record) or evaluate a technical approach for the project. Intended for dispatch from Codex automation or Claude routines; GitHub trigger phrase: @vfs-s3-bot please prepare design doc Use when this capability is needed.
基于 SOC 职业分类
正在显示 SKILL.md
| name | rust-api-design |
| description | | Use when this capability is needed. |
Expert guide for designing idiomatic, clean, robust, and forward-compatible APIs in Rust.
Use the type system to enforce valid state transitions at compile time instead of running checks at runtime.
// States
pub struct Draft;
pub struct Sent;
pub struct Email<State> {
recipient: String,
body: String,
_marker: std::marker::PhantomData<State>,
}
impl Email<Draft> {
pub fn new(recipient: String, body: String) -> Self {
Self { recipient, body, _marker: std::marker::PhantomData }
}
pub fn send(self) -> Email<Sent> {
Email {
recipient: self.recipient,
body: self.body,
_marker: std::marker::PhantomData,
}
}
}
Use builder structs to handle complex creation logic, and mark the build step with #[must_use].
pub struct Server {
host: String,
port: u16,
}
#[derive(Default)]
pub struct ServerBuilder {
host: Option<String>,
port: Option<u16>,
}
impl ServerBuilder {
pub fn host(mut self, host: String) -> Self {
self.host = Some(host);
self
}
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
#[must_use = "builders must be executed to construct the target type"]
pub fn build(self) -> Result<Server, &'static str> {
let host = self.host.ok_or("Host required")?;
let = .port.();
(Server { host, port })
}
}
Prevent downstream crates from implementing public traits by referencing a private marker trait.
mod private {
pub trait Sealed {}
}
// Seal the trait by requiring the private Sealed supertrait
pub trait SafeMath: private::Sealed {
fn safe_add(&self, other: &Self) -> Option<Self> where Self: Sized;
}
// Only implement for trusted types
impl private::Sealed for i32 {}
impl SafeMath for i32 {
fn safe_add(&self, other: &Self) -> Option<Self> {
self.checked_add(*other)
}
}
Add methods to external types without violating orphan rules.
pub trait StringExt {
fn is_alphanumeric_only(&self) -> bool;
}
impl StringExt for String {
fn is_alphanumeric_only(&self) -> bool {
self.chars().all(|c| c.is_alphanumeric())
}
}
Encode validity constraints into the type system itself to avoid repeated run-time checks.
// Bad: validates strings dynamically on every function call
fn process_email(email: &str) { ... }
// Good: parsing parses into a type-safe wrapper representing verified validity
pub struct EmailAddress(String);
impl std::str::FromStr for EmailAddress {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.contains('@') {
Ok(EmailAddress(s.to_string()))
} else {
Err("Invalid email format")
}
}
}
#[must_use]: Annotate fallible or side-effect-free functions (e.g. builders, getters, calculations) to warn users when their outputs are ignored.#[non_exhaustive]: Annotate public enums and structs to allow adding new variants/fields in patch updates without breaking downstream crates.From over Into: Implementing From<T> automatically generates Into<T>. Only implement Into when converting to external types where From cannot be implemented due to orphan rules.Default: If a struct provides a parameterless new(), implement Default to match idiomatic conventions.AsRef and Borrow: Use AsRef<T> for cheap conversions to reference types, and reserve Borrow<T> for cases where the target has matching hash/equality semantics (e.g., hash keys).Debug: Implement or derive Debug on all public types to enable trouble-free integration and logging.Clone & PartialEq when logical to do so, facilitating tests and standard collection handling.Use strict API discipline for anything exported from a crate boundary. Internal modules can move faster, but still keep invariants local.
// Public: stable, documented, forward-compatible
pub fn connect(config: ConnectConfig) -> Result<Client, ConnectError>;
// Internal: can be narrower and more direct
pub(crate) fn connect_with_parts(addr: SocketAddr, tls: TlsMode) -> io::Result<Socket>;
Use generics for zero-cost static dispatch and trait objects for runtime-selected behavior.
pub fn encode_with<C: Codec>(codec: C, data: &[u8]) -> Vec<u8> { codec.encode(data) }
pub fn encode_dyn(codec: &dyn Codec, data: &[u8]) -> Vec<u8> { codec.encode(data) }
Use new for required arguments only. Use builders for optional parameters, validation, or future growth.
// Strong typing prevents mixing unrelated IDs
pub struct UserId(pub Uuid);
pub struct OrderId(pub Uuid);
// These cannot be accidentally compared or swapped
// But still derive useful traits
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TenantId(pub Uuid);
#[derive(Debug, thiserror::Error)]
pub enum ConnectError {
#[error("address {addr} is not reachable")]
Unreachable { addr: SocketAddr },
#[error("TLS handshake failed")]
Tls(#[from] rustls::Error),
#[error("connection timed out after {0:?}")]
Timeout(Duration),
}
impl ConnectError {
/// True if the caller should retry.
pub fn is_retryable(&self) -> bool {
matches!(self, Self::Unreachable { .. } | Self::Timeout(_))
}
}
// Good: async fn is clear about being async
pub async fn fetch_user(id: UserId) -> Result<User, Error> { /* ... */ }
// Good: generic over executor
pub async fn run_with<C: Executor>(client: &C) -> Result<(), Error> { /* ... */ }
Don't hide blocking work behind async fn. Document if the method may block.
[features]
default = ["json"]
json = ["serde", "serde_json"]
full = ["json", "grpc", "tls"]
| Pattern | Convention | Example |
|---|---|---|
| Constructors | new() | Client::new() |
| Builders | builder() | Client::builder() |
| Getters | field name | client.host() |
| Setters | set_ prefix | client.set_host() |
| Boolean getters | is_, has_, can_ | client.is_connected() |
| Conversions | to_ / into_ / as_ | to_string() / into_inner() / as_ref() |
| Iterators | plural of item | users() returns impl Iterator<Item = &User> |
doc(cfg).#[non_exhaustive].Self.// Bad: exposes chosen hash map implementation
pub fn users(&self) -> &hashbrown::HashMap<UserId, User>;
// Better: expose behavior
pub fn get_user(&self, id: UserId) -> Option<&User>;
pub fn user_ids(&self) -> impl Iterator<Item = UserId> + '_;
// Bad
client.connect(true, false);
// Better
client.connect(ConnectOptions { tls: TlsMode::Required, retry: RetryMode::Disabled });
StringAccept &str for reading and impl Into<String> for storing.
Box<dyn Error>// Bad: callers cannot match on specific errors
pub fn connect() -> Result<(), Box<dyn std::error::Error>>;
// Good: typed errors allow recovery
pub fn connect() -> Result<(), ConnectError>;
When reviewing Rust API design, inspect naming, ownership, error types, semver stability, feature flags, and whether invalid states can be constructed by safe callers.
Source: adxptived/Rust-Skills — distributed by TomeVault.