本文へ移動
cccskills
無料GitHub で公開

advanced-rust-patterns

Expert-level idiomatic Rust API design — the patterns that make illegal states unrepresentable and abstractions zero-cost. Type-state programming (PhantomData state machines), newtype + sealed + extension traits, typestate builders, RAII guards & Drop ordering, the interior-mutability decision tree (Cell/RefCell/Mutex/RwLock/Atomic/OnceLock), enum-driven state machines, error architecture (thiserror vs anyhow), dyn vs generic dispatch & object safety, the impl Trait / GAT / RPITIT toolbox, and Deref-for-smart-pointers (and its abuse). Use when designing a Rust library's public API, encoding invariants in the type system, choosing a dispatch or error strategy, or reviewing Rust for idiom. NOT for borrow-checker firefighting / toolchain / test-runner workflow (use rust-development-workflow), NOT for pd-console GPUI rendering/layout/panes (use gpui-rust-console), NOT for app packaging/notarization (use rust-app-distribution).

インストール方法を見る

含まれるファイル(9)

  • SKILL.md13.3 KB
  • examples/error_architecture.rs5.0 KB
  • examples/INDEX.md935 B
  • examples/typestate_request.rs3.1 KB
  • references/01-type-state-and-newtypes.md11.9 KB
  • references/02-interior-mutability-and-raii.md9.4 KB
  • references/03-error-architecture.md7.1 KB
  • references/04-dispatch-and-traits.md9.3 KB
  • references/INDEX.md1.5 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Advanced Rust Patterns

Activation boundary: use this for public API invariants, trait contracts, dispatch, error types, and state modeling. If the central question is which container owns related data, route to rust-data-structures-advanced. If an existing path is slow, route to rust-performance-and-idioms. Routine compiler feedback belongs to rust-development-workflow.

The patterns here share one thesis: push correctness into the type system so the compiler rejects misuse, then make the abstraction cost nothing at runtime. A type-state builder makes a missing required field a compile error, not a runtime panic. A sealed trait lets you add methods later without breaking downstream. A newtype NodeId(String) makes "passing a DAG id where a skill id is expected" stop compiling. None of it shows up in the generated assembly. This skill is for API design and idiom, not for fighting the borrow checker (that is rust-development-workflow) — it assumes you already write compiling Rust and want it to be unmistakable.

When to Use

✅ Use for:

  • Designing a library's public surface: traits, newtypes, builders, error types
  • Encoding a state machine or protocol so invalid transitions don't compile
  • Choosing interior mutability (Cell vs RefCell vs Mutex/RwLock vs atomics vs OnceLock)
  • Deciding dyn Trait vs <T: Trait> (object safety, dispatch cost) — e.g. a Box<dyn Pane> registry
  • Error architecture: thiserror enum for a library vs anyhow for a binary
  • Reaching for impl Trait / GATs / RPITIT and knowing the API-compatibility footguns
  • Reviewing Rust for idiom ("is this Deref a smart pointer or fake inheritance?")

❌ NOT for:

  • Borrow-checker errors, async lifetime puzzles, cargo/clippy/test workflow → rust-development-workflow
  • GPUI rendering, Taffy layout, pane/Block contract in core/pd-console → gpui-rust-console
  • Shipping/signing/notarizing a macOS Rust app → rust-app-distribution
  • Generic "how do I learn Rust" — this is expert idiom, not a tutorial

Decision Points

flowchart TD
  Q["What are you designing?"] --> SM{"A state machine<br/>or protocol?"}
  SM -->|"states known at compile time,<br/>caller drives transitions"| TS["Type-state: PhantomData‹S›<br/>+ transitions that consume self<br/>→ ref 01"]
  SM -->|"states change at runtime<br/>from data/events"| EN["enum State + match<br/>(data-driven) → ref 02"]
  Q --> WRAP{"Wrapping a value<br/>to add meaning/<br/>invariant/trait?"}
  WRAP -->|"distinct type, hide repr"| NT["Newtype + sealed/extension traits<br/>→ ref 01"]
  WRAP -->|"many optional ctor params"| BU["Typestate builder (bon/typed-builder)<br/>→ ref 01"]
  Q --> MUT{"Need to mutate<br/>through a shared ref?"}
  MUT -->|"single thread"| ST{"Copy / whole-value?"}
  ST -->|yes| CELL["Cell‹T› (never panics) → ref 02"]
  ST -->|no| RC["RefCell‹T› (runtime borrow, can panic) → ref 02"]
  MUT -->|"multi thread"| MT{"Access shape?"}
  MT -->|"one counter/flag"| AT["Atomic → ref 02"]
  MT -->|"many read / rare write"| RW["RwLock → ref 02"]
  MT -->|"exclusive"| MX["Mutex → ref 02"]
  MT -->|"init once, read forever"| OL["OnceLock / LazyLock → ref 02"]
  Q --> ERR{"Producing errors?"}
  ERR -->|"library — callers match variants"| TE["thiserror enum, #[from] → ref 03"]
  ERR -->|"app/binary — just bubble up"| AN["anyhow + .context() → ref 03"]
  Q --> DISP{"Calling a trait method<br/>on heterogeneous types?"}
  DISP -->|"collection of mixed types,<br/>plugin registry"| DYN["Box‹dyn Trait› — check object safety → ref 04"]
  DISP -->|"hot path, one type per call site"| GEN["Generic ‹T: Trait› (monomorphized) → ref 04"]

Core Capabilities

PatternUse it to…Replaces the anti-pattern…Ref
Type-stateMake invalid call order a compile errorRuntime assert!(self.initialized)01
NewtypeGive a primitive identity + invariantsPassing bare String/u64 everywhere (stringly-typed)01
Sealed traitAdd trait methods later, non-breakingA trait downstream can implement, freezing your API01
Extension traitAdd methods to a foreign typeA free fn that reads worse at the call site01
Typestate builderForce required fields at compile timeDefault + runtime "field X was None" panic01
RAII guardTie cleanup to scope exitManual unlock()/close() you can forget02
Interior mutabilityMutate through &self, the right wayReaching for unsafe or Arc<Mutex> reflexively02
Enum state machineModel runtime states exhaustivelyA pile of bools + Options (illegal combos)02
thiserror / anyhowMatch the error tool to lib vs appBox<dyn Error> everywhere, or .unwrap()03
dyn vs genericTrade dispatch cost vs code size knowinglyCargo-culting Box<dyn> into a hot loop04
impl Trait / GATName unnameable types; lend borrowsBoxing a closure/iterator you didn't need to04
Deref (smart ptr)Transparent pointer-like wrapperDeref as fake inheritance (deref polymorphism)04

Anti-Patterns (Novice vs Expert)

Stringly-typed / primitive-obsessed IDs

Novice: fn run(node_id: String, dag_id: String) — two Strings, easy to swap. Expert: NodeId(String) and DagId(String) newtypes. run(dag, node) vs run(node, dag) now fails to compile. Zero runtime cost; the wrapper is erased. (In a gpui pane registry, PaneId(u16) vs a raw nav index prevents the classic "NAV slot != producer slot" bug from even type-checking.) See ref 01. Detection: public functions taking ≥2 same-typed primitive params that mean different things.

Arc<Mutex<T>> as the reflexive answer to "shared mutable state"

Novice: wrap everything in Arc<Mutex<T>> so "any thread can touch it." Expert: walk the decision tree. Single thread? Cell/RefCell — no lock at all. One integer across threads? AtomicU64. Read-mostly? RwLock. Init-once-read-forever? OnceLock. A Mutex held across an .await or a render call is the canonical multi-agent / GPUI stall. See ref 02. Detection: Mutex/RwLock chosen before the access pattern (Copy? read/write ratio? thread count?) was named.

Deref to fake inheritance ("deref polymorphism")

Novice: impl Deref for Wrapper { type Target = Inner; … } so wrapper.inner_method() "just works." Expert: Deref means smart pointer — "what's inside the box." Using it for inheritance is implicit magic with no true subtyping: trait bounds on Inner do not apply to Wrapper, and inside Inner::method self is Inner, not Wrapper, so nothing overrides. Use a real method or trait. The std docs themselves warn to implement Deref "only when deref coercion is desirable." See ref 04. Detection: a Deref impl whose Target is not a thing the type contains-as-a-pointer.

Option<T> to "make a builder field optional" (with typed-builder)

Novice: assumes wrapping a field in Option makes the builder skip it. Expert: in typed-builder, fields are required by default — Option<T> is still required unless you write #[builder(default)]. (In bon, Option<T> is auto-optional — the two crates differ, and assuming the wrong one is a real bug.) The whole point of a typestate builder is that .build() does not exist as a method until every required slot is set. See ref 01. Detection: a #[derive(TypedBuilder)] field that's Option<T> with no #[builder(default)] and the author expected it optional.

Quality Gates

□ No public fn takes two same-typed primitives meaning different things (newtype them) — ref 01
□ Traits meant to stay closed are sealed (private::Sealed supertrait) — ref 01
□ State machines: compile-time order → typestate; runtime data → enum + exhaustive match — ref 01/02
□ Interior mutability picked from the access pattern, not by habit (Cell/RefCell/Atomic/RwLock/Mutex/OnceLock) — ref 02
□ No lock (Mutex/RwLock guard, RefCell borrow) held across .await or a render/notify call — ref 02
□ Drop order understood: struct fields drop in declaration order; locals in REVERSE — ref 02
□ Never call .drop() (E0040); use std::mem::drop(x) — ref 02
□ Library errors = thiserror enum (matchable, #[from] for ?); binary errors = anyhow + .context() — ref 03
□ No anyhow::Error in a library's PUBLIC return type (callers can't match) — ref 03
□ dyn vs generic chosen on object-safety + dispatch cost, not reflex; check dyn-compatibility rules — ref 04
□ Deref implemented ONLY for smart-pointer-like wrappers, never for inheritance — ref 04
□ Any type with an unused generic/lifetime param carries the right PhantomData marker (variance/dropck/Send) — ref 01
□ cargo clippy -- -W clippy::pedantic is clean on the new API surface

Worked Example — A typestate connection that can't be misused

A Connection that must be opened before a request is sent, and where calling request() on a closed connection is a compile error, not a runtime check.

use std::marker::PhantomData;

// Uninhabited markers: no value of these can ever exist — state is purely type-level.
enum Closed {}
enum Open {}

struct Connection<S> {
    socket: TcpStream,
    _state: PhantomData<S>,
}

impl Connection<Closed> {
    fn connect(addr: &str) -> std::io::Result<Connection<Open>> {
        let socket = TcpStream::connect(addr)?;
        Ok(Connection { socket, _state: PhantomData })
    }
}

impl Connection<Open> {
    // request() exists ONLY in the Open state.
    fn request(&mut self, body: &[u8]) -> std::io::Result<Vec<u8>> { /* ... */ }

    // close() consumes self -> the Open handle is gone, so you cannot request() after.
    fn close(self) -> Connection<Closed> {
        Connection { socket: self.socket, _state: PhantomData }
    }
}

What the novice would do: a bool is_open field and if !self.is_open { panic!("closed") } at the top of request(). That defers the error to runtime and to whoever hits that path in prod.

What the expert gets: Connection::<Closed> literally has no request method, and close(self) moves the Open handle away, so use-after-close fails at compile time. The PhantomData<S> is zero-sized — size_of::<Connection<Open>>() == size_of::<Connection<Closed>>(). The pattern shows up in bon/typed-builder (states = "which required fields are set yet") and in protocol clients. Full walkthrough, including the builder application and the variance table, in ref 01.

Reference Files

FileConsult When
references/01-type-state-and-newtypes.mdTypestate state machines, newtype + sealed + extension traits, typestate builders (bon/typed-builder), PhantomData & variance
references/02-interior-mutability-and-raii.mdCell/RefCell/Mutex/RwLock/Atomic/OnceLock decision tree, RAII guards, Drop ordering & mem::drop, enum-driven runtime state machines
references/03-error-architecture.mdthiserror vs anyhow, error enums, ?/From desugaring, .context(), library-vs-app boundary
references/04-dispatch-and-traits.mddyn vs generic dispatch, object safety / dyn-compatibility rules, monomorphization tradeoffs, impl Trait / GAT / RPITIT, Deref for smart pointers + the anti-pattern

Examples

ExampleWalks Through
examples/typestate_request.rsCompilable type-state HTTP request builder — invalid order won't compile
examples/error_architecture.rsthiserror library enum flowing into an anyhow application boundary via ? + .context()

Sources

Every snippet in this skill is traceable to an official or canonical source — the Rust API Guidelines, the Rust Reference, the Rustonomicon, the std docs, the rust-unofficial Rust Design Patterns book, docs.rs crate docs (thiserror, anyhow, bon, typed-builder), and the Rust release blog (GATs 1.65, RPITIT 1.75). Each reference file carries inline URLs at the point of use.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Expert in 2000s-era music visualization (Milkdrop, AVS, Geiss) and modern WebGL implementations. Specializes in Butterchurn integration, Web Audio API AnalyserNode FFT data, GLSL shaders for audio-reactive visuals, and psychedelic generative art. Activate on "Milkdrop", "music visualization", "WebGL visualizer", "Butterchurn", "audio reactive", "FFT visualization", "spectrum analyzer". NOT for simple bar charts/waveforms (use basic canvas), video editing, or non-audio visuals.

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月8日 更新

Expert legal research agent for finding and scraping expungement data state by state. Knows authoritative sources, URL patterns, Firecrawl configuration, and 2026 legal landscape.

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月8日 更新

Expert in 3D computer vision labeling tools, workflows, and AI-assisted annotation for LiDAR, point clouds, and sensor fusion. Covers SAM4D/Point-SAM, human-in-the-loop architectures, and vertical-specific training strategies. Activate on '3D labeling', 'point cloud annotation', 'LiDAR labeling', 'SAM 3D', 'SAM4D', 'sensor fusion annotation', '3D bounding box', 'semantic segmentation point cloud'. NOT for 2D image labeling (use clip-aware-embeddings), general ML training (use ml-engineer), video annotation without 3D (use computer-vision-pipeline), or VLM prompt engineering (use prompt-engineer).

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月8日 更新

Apply crisis decision-making research to agent routing, uncertainty triage, and coordination failure analysis in time-pressured systems. Use when diagnosing handoff failures, analytical paralysis, or expert judgment under incomplete information. NOT for routine coding, simple CRUD design, or static single-agent tasks with complete information.

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月8日 更新

Use for insight, reframing, contradiction, impasse, and anomaly-driven problem solving when execution effort no longer helps. NOT for routine optimization, error correction, or well-specified tasks with known solution paths.

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月8日 更新

Apply cognitive task analysis to expert work that depends on perceptual cues, branching judgment, and recurring monitoring loops. Use when decomposing expert capability into agent structure, simulation design, or validation interviews. NOT for ordinary step-by-step SOP capture or simple pipelines with no tacit cue layer.

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月8日 更新

curiositech のスキルをすべて見る

このスキルの問題を報告する