Skip to main content

rust

Strict set of rules in terms of codebase development, design patterns, and best practices. Use when the user wants to develop a new feature or refactor existing code.

インストールへ移動

ソース情報

リポジトリ
databricks-solutions/apx
ソースの最終更新活動
2026年3月30日 21:34
検出された SKILL.md の言語
英語
スター
89
フォーク
25

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
rust
description
Strict set of rules in terms of codebase development, design patterns, and best practices. Use when the user wants to develop a new feature or refactor existing code.
## Principles Priority: **Correctness > Safety > Readability > Performance** - **Idiomatic Rust.** Follow standard library conventions. If the stdlib does it one way, do it that way. - **Leverage the type system.** Encode invariants in types, not runtime checks. Make illegal states unrepresentable. - **Domain-driven design.** Name everything in the language of the problem, not the implementation. - **Reuse existing libraries and frameworks** when possible. ## Safety rules Adapted from [The Power of Ten](https://en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Developing_Safety-Critical_Code) (Holzmann) for Rust. 1. **Simple control flow.** No nested if-else, no nested loops. Split into single-purpose functions. Max one level of branching per function body. 2. **Short functions.** No function longer than ~60 lines. If it's too long, decompose it. 3. **Fixed loop bounds.** All loops must have a provable upper bound. Prefer iterators (`for x in collection`) over manual `while i < len` with index arithmetic. 4. **Minimal allocation.** Prefer `&str` over `String`, slices over `Vec`, borrows over clones. Allocate only when you must own. 5. **Assertions at boundaries.** Use `debug_assert!` for invariants within functions. Validate inputs at public API boundaries with `Result`/`Option`, not panics. 6. **Smallest possible scope.** Variables, types, and functions should be visible only where needed. Prefer module-private by default; add `pub` only when required. 7. **Handle all return values.** Never discard `Result`. Use `?` propagation or explicit handling. Annotate intentional ignores with `let _ =`. 8. **Macros sparingly.** Prefer generics, traits, and enums over procedural macros. Macros obscure control flow and complicate debugging. 9. **Domain types over raw primitives.** Wrap repetitive low-level operations in a named type instead of scattering the same logic across functions. ```rust // bad — raw index arithmetic repeated everywhere let mut i = 0; while i < bytes.len() { if bytes[i] == target { return i; } i += 1; } // good — domain cursor encapsulates iteration let mut scanner = Scanner::new(bytes); while let Some(b) = scanner.peek() { if b == target { return scanner.position(); } scanner.advance(); } ``` 10. **Zero warnings.** Code must compile with `#[deny(warnings)]` cleanly. Run `cargo clippy` and address all lints. 11. **Use `#[expect(lint, reason = "...")]` instead of `#[allow]`.** `#[expect]` warns when the suppression becomes unnecessary, preventing stale silencing. Always include a `reason` string. *(M-LINT-OVERRIDE-EXPECT)* 12. **Panics mean stop the program.** Panics are not exceptions. Never use `panic!`, `unwrap()`, or `unreachable!()` for recoverable errors — use `Result`. `expect()` is acceptable only for proven invariants with a descriptive message. *(M-PANIC-IS-STOP)* 13. **`unsafe` only when required by 3rd-party libraries** (e.g. PyO3 macros). No other reasons to write unsafe code. ## Naming conventions *Sources: Rust API Guidelines C-CONV, C-GETTER; Microsoft M-CONCISE-NAMES* - **Conversion prefixes follow ownership semantics:** - `as_` — cheap reference-to-reference (no allocation, no copy) - `to_` — expensive conversion, may allocate (e.g. `to_string()`) - `into_` — consumes self, returns owned value - **No `get_` prefix on getters.** Use `fn name(&self) -> &str`, not `fn get_name()`. - **Implement `From<T>`, never `Into<T>`.** The blanket impl gives you `Into` for free. - **Concise type names.** Avoid hollow suffixes: `Service`, `Manager`, `Factory`, `Handler`, `Processor`. If the name needs a suffix, the type does too much. - **Named constants over magic literals.** Every literal with domain meaning gets a `const` with a doc comment. No bare numbers, bytes, or strings in logic. ```rust // bad if b == b'\\' { i += 2; } // good const ESCAPE_BYTE: u8 = b'\\'; if b == ESCAPE_BYTE { scanner.skip_escaped(); } ``` ## Error handling *Sources: Microsoft M-APP-ERROR, M-ERRORS-CANONICAL-STRUCTS* - **`thiserror` for library crates, `anyhow`/`eyre` for application crates.** Libraries expose structured errors; apps just need context chains. - **Error messages: lowercase, no trailing punctuation.** Matches `std` convention for composable `.context()` chains. - **Use `?` propagation everywhere.** Avoid `match` on `Result` when `?` + `.map_err()` suffices. - **Never `unwrap()` in non-test code.** Use `expect("reason")` only for proven invariants. - **Canonical error struct pattern:** ```rust #[derive(Debug, thiserror::Error)] pub enum ParseError { #[error("invalid token at position {position}")] InvalidToken { position: usize, token: char }, #[error("unexpected end of input")] UnexpectedEof, #[error(transparent)] Io(#[from] std::io::Error), } ``` ## Domain-driven design Adapted from [Domain-Driven Design](https://martinfowler.com/bliki/DomainDrivenDesign.html) (Evans/Fowler) for Rust. ### Ubiquitous language Name types, functions, and modules in the language of the problem domain, not the implementation. ```rust // bad — describes implementation mechanics fn find_end_offset(s: &str) -> Option<usize> fn check_string(s: &str) -> bool // good — describes domain concepts fn PaymentResult::validate(invoice: &Invoice) -> Option<PaymentResult> fn ClassName::is_tailwind(token: &str) -> bool ``` ### Value objects as structs Domain values without identity are structs. Functions take `&Struct` and return new structs — no mutation through output parameters. ```rust // bad — caller provides mutable buffer fn process(input: &Config, out: &mut String) // good — function returns a value object fn process(input: &Config) -> ProcessResult ``` ### Enums for closed domain rules When a domain has a fixed set of variants or checks, use an enum — not trait objects, not loose functions. ```rust // bad — scattered functions, no unifying type fn is_not_empty(s: &str) -> bool { ... } fn starts_with_letter(s: &str) -> bool { ... } // good — enum variants are self-documenting and composable enum ValidationRule { NonEmpty, StartsWithLetter, ContainsHyphen } impl ValidationRule { fn passes(self, input: &str) -> bool { match self { ... } } } const RULES: &[ValidationRule] = &[ValidationRule::NonEmpty, ...]; ``` ### Traits for open abstractions Use traits when behavior needs to be extended by future implementations. Start with the trait, then implement concrete types. ```rust // bad — parallel standalone functions fn run_git_cmd() -> Output { ... } fn run_uv_cmd() -> Output { ... } // good — shared trait, separate implementations trait ExternalCommand { fn execute(&self) -> Result<Output>; } impl ExternalCommand for Git { ... } impl ExternalCommand for Uv { ... } ``` *See also [Service & middleware](#service--middleware) and [Trait object plugin](#trait-object-plugin) in Ecosystem patterns.* ### Modules as bounded contexts Each Rust module is a bounded context. Types and functions within a module share a domain model; the module boundary is the public API. Keep internal helpers private. ### Sans-I/O: separate protocol logic from transport *Source: [sans-io.readthedocs.io](https://sans-io.readthedocs.io/how-to-sans-io.html)* Protocol logic (parsing, validation, state machines, data transformation) must be pure functions or types that take data in and return data out — no sockets, no channels, no async, no file handles. I/O operations (network, channels, disk) live in a thin outer layer that calls the protocol layer. This makes protocol logic testable without standing up real infrastructure, reusable across different I/O backends (tokio, crossbeam, sync), and composable across boundaries (Rust ↔ Python). ```rust // bad — protocol parsing entangled with channel I/O impl SlotSend { fn __call__(&self, py, event: &PyDict) -> PyResult<...> { let type_val: String = event.get_item("type")?.extract()?; match type_val.as_str() { "http.response.start" => { let status = event.get_item("status")?.extract()?; *self.status.lock() = Some(status); // parse headers here too... } "http.response.body" => { let body = event.get_item("body")?.extract()?; self.outbound_tx.send(OutboundSlot { ... })?; // I/O mixed in self.body_tx.send(body)?; // I/O mixed in } } } } // good — protocol layer is a pure function, I/O layer calls it enum SendEvent { Start { status: u16, headers: Vec<(Bytes, Bytes)> }, Body { data: Bytes, more_body: bool }, } fn parse_send_event(event: &Bound<'_, PyDict>) -> PyResult<SendEvent> { // pure — no channels, no async, testable with synthetic PyDicts } impl SlotSend { fn __call__(&self, py, event: &PyDict) -> PyResult<...> { let parsed = parse_send_event(event)?; // protocol self.dispatch(parsed) // I/O } } ``` The same principle applies to request classification: ```rust // bad — routing decision mixed with hyper I/O async fn handle(self, req: Request<Incoming>) -> Response<...> { if req.uri().path() == "/_health/alive" { return json_response(HEALTH_ALIVE); // mixed: decision + response construction } if is_websocket_upgrade(&req) { return self.dispatch.dispatch_ws(req).await; // mixed: decision + dispatch } // ... semaphore, timeout, dispatch ... } // good — classification is a pure function enum RequestKind { Probe(ProbeKind), WebSocket, Http, } fn classify(path: &str, headers: &HeaderMap) -> RequestKind { // pure — no async, no Response construction, testable with strings } async fn handle(self, req: Request<Incoming>) -> Response<...> { match classify(req.uri().path(), req.headers()) { RequestKind::Probe(kind) => probe_response(kind), RequestKind::WebSocket => self.dispatch.dispatch_ws(req).await, RequestKind::Http => self.dispatch_http(req).await, } } ``` **Rule of thumb:** if a function touches both data transformation AND a channel/socket/file, split it. The data transformation half is the protocol layer; the channel/socket half is the I/O layer. The protocol layer should be testable with `#[test]` using synthetic inputs — no `#[tokio::test]`, no channels, no `Python::attach`. ## API design *Sources: Microsoft M-INIT-BUILDER, M-IMPL-ASREF, M-IMPL-IO, M-AVOID-WRAPPERS; Rust API Guidelines C-COMMON-TRAITS* - **Builder pattern for complex initialization.** When a type has 4+ optional configuration fields, provide a builder instead of a constructor with many parameters. - **Accept `impl AsRef<str>` / `impl AsRef<Path>`** over concrete `&str`/`String`/`&Path` in function params when callers may have either type. - **Accept `impl Read` / `impl Write` for I/O functions.** Decouples logic from concrete I/O sources — enables testing with `Cursor<Vec<u8>>`. - **Avoid smart pointers in public APIs.** Don't expose `Arc<Mutex<T>>`, `Box<T>`, `Rc<T>` — let callers choose their wrapping strategy. - **Eagerly implement common traits:** `Debug`, `Clone`, `PartialEq`, `Default` on all public types. *(C-COMMON-TRAITS)* - **All public types must implement `Debug`.** No exceptions. *(M-PUBLIC-DEBUG)* - **Avoid unnecessary `Copy`.** Do not derive or implement `Copy` unless the type genuinely benefits from implicit copy semantics. Prefer `Clone` with explicit `.clone()` so copies are visible and intentional. ## Code patterns ### Return values, don't mutate Functions return domain types instead of writing into `&mut` parameters. This makes data flow explicit and enables composition via `.map()`, `.fold()`, iterators. ```rust // bad — mutation hides data flow fn transform(input: &str, out: &mut Vec<String>) // good — return value makes flow explicit fn transform(input: &str) -> Vec<TransformResult> ``` ### Flat validation with early returns Split complex validation into a scanning step and a checking step. Each is its own function. No nesting beyond one level. ```rust // bad — nested ifs, multiple concerns in one block if b == CLOSE { if i + 1 < len && bytes[i + 1] == CLOSE { if i == 0 { return None; } return Some(i); } return None; } // good — scan finds candidate, validate checks it fn scan(input: &str) -> Option<Boundary> { ... } // walks bytes fn validate(pos: usize, bytes: &[u8]) -> Option<Boundary> { ... } // checks invariants ``` ### Iterator chains over indexed loops Prefer `.iter()`, `.map()`, `.filter()`, `.collect()` over `for i in 0..len` with manual indexing. Iterator chains are bounds-checked by construction. ### `Cow<'a, str>` for conditional ownership
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る