oxlsx 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oxlsx-0.1.0/.agents/skills/rust-coding/SKILL.md +440 -0
- oxlsx-0.1.0/.agents/skills/rust-coding/SKILL_EN.md +88 -0
- oxlsx-0.1.0/.agents/skills/rust-coding/SKILL_ZH.md +236 -0
- oxlsx-0.1.0/.agents/skills/rust-coding/agents/openai.yaml +4 -0
- oxlsx-0.1.0/.agents/skills/rust-performance/SKILL.md +382 -0
- oxlsx-0.1.0/.agents/skills/rust-performance/SKILL_EN.md +64 -0
- oxlsx-0.1.0/.agents/skills/rust-performance/SKILL_ZH.md +351 -0
- oxlsx-0.1.0/.agents/skills/rust-performance/agents/openai.yaml +4 -0
- oxlsx-0.1.0/.agents/skills/rust-type-driven/SKILL.md +431 -0
- oxlsx-0.1.0/.agents/skills/rust-type-driven/SKILL_EN.md +59 -0
- oxlsx-0.1.0/.agents/skills/rust-type-driven/SKILL_ZH.md +205 -0
- oxlsx-0.1.0/.agents/skills/rust-type-driven/agents/openai.yaml +4 -0
- oxlsx-0.1.0/.github/workflows/benchmarks.yml +74 -0
- oxlsx-0.1.0/.github/workflows/ci.yml +39 -0
- oxlsx-0.1.0/.github/workflows/opencode.yml +33 -0
- oxlsx-0.1.0/.github/workflows/release.yml +169 -0
- oxlsx-0.1.0/.gitignore +14 -0
- oxlsx-0.1.0/AGENTS.md +92 -0
- oxlsx-0.1.0/Cargo.lock +1174 -0
- oxlsx-0.1.0/Cargo.toml +46 -0
- oxlsx-0.1.0/LICENSE-APACHE +188 -0
- oxlsx-0.1.0/LICENSE-MIT +21 -0
- oxlsx-0.1.0/PKG-INFO +277 -0
- oxlsx-0.1.0/README.md +251 -0
- oxlsx-0.1.0/SPEC.md +162 -0
- oxlsx-0.1.0/benches/openpyxl_comparison.py +135 -0
- oxlsx-0.1.0/benches/read_benchmarks.rs +123 -0
- oxlsx-0.1.0/benches/write_benchmarks.rs +92 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-07-oxlsx-phase12b-comments/design.md +121 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-07-oxlsx-phase12b-comments/proposal.md +62 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-07-oxlsx-phase12b-comments/specs/worksheet-comments/spec.md +61 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-07-oxlsx-phase12b-comments/tasks.md +55 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-07-oxlsx-phase13-freeze-panes/tasks.md +41 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-07-oxlsx-phase13-print-settings/tasks.md +39 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-13-oxlsx-phase13-tables/design.md +70 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-13-oxlsx-phase13-tables/proposal.md +69 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-13-oxlsx-phase13-tables/specs/worksheet-tables/spec.md +109 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-13-oxlsx-phase13-tables/tasks.md +59 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-14-oxlsx-phase12a-hyperlinks/design.md +88 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-14-oxlsx-phase12a-hyperlinks/proposal.md +70 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-14-oxlsx-phase12a-hyperlinks/specs/worksheet-hyperlinks/spec.md +111 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-14-oxlsx-phase12a-hyperlinks/tasks.md +141 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-14-oxlsx-table-lossless-rmw/design.md +99 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-14-oxlsx-table-lossless-rmw/proposal.md +76 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-14-oxlsx-table-lossless-rmw/specs/worksheet-tables/spec.md +87 -0
- oxlsx-0.1.0/openspec/changes/archive/2026-06-14-oxlsx-table-lossless-rmw/tasks.md +79 -0
- oxlsx-0.1.0/openspec/changes/oxlsx-phase4-write/tasks.md +54 -0
- oxlsx-0.1.0/openspec/specs/worksheet-comments/spec.md +55 -0
- oxlsx-0.1.0/openspec/specs/worksheet-hyperlinks/spec.md +111 -0
- oxlsx-0.1.0/openspec/specs/worksheet-print-settings/spec.md +101 -0
- oxlsx-0.1.0/openspec/specs/worksheet-tables/spec.md +166 -0
- oxlsx-0.1.0/pyproject.toml +37 -0
- oxlsx-0.1.0/samples/.DS_Store +0 -0
- oxlsx-0.1.0/samples/.atl/.skill-registry.cache.json +3 -0
- oxlsx-0.1.0/samples/.atl/skill-registry.md +118 -0
- oxlsx-0.1.0/samples/bench_10k.xlsx +0 -0
- oxlsx-0.1.0/samples/comments.xlsx +0 -0
- oxlsx-0.1.0/samples/hyperlinks.xlsx +0 -0
- oxlsx-0.1.0/samples/inline_strings_no_sst.xlsx +0 -0
- oxlsx-0.1.0/samples/multi_sheet.xlsx +0 -0
- oxlsx-0.1.0/samples/tables.xlsx +0 -0
- oxlsx-0.1.0/samples/tables_totals.xlsx +0 -0
- oxlsx-0.1.0/samples/test.xlsx +0 -0
- oxlsx-0.1.0/samples/unzipped/[Content_Types].xml +2 -0
- oxlsx-0.1.0/samples/unzipped/_rels/.rels +1 -0
- oxlsx-0.1.0/samples/unzipped/docProps/app.xml +1 -0
- oxlsx-0.1.0/samples/unzipped/docProps/core.xml +1 -0
- oxlsx-0.1.0/samples/unzipped/xl/_rels/workbook.xml.rels +1 -0
- oxlsx-0.1.0/samples/unzipped/xl/jsaProject.bin +1 -0
- oxlsx-0.1.0/samples/unzipped/xl/sharedStrings.xml +1 -0
- oxlsx-0.1.0/samples/unzipped/xl/styles.xml +1 -0
- oxlsx-0.1.0/samples/unzipped/xl/theme/theme.xml +1 -0
- oxlsx-0.1.0/samples/unzipped/xl/theme/theme1.xml +1 -0
- oxlsx-0.1.0/samples/unzipped/xl/workbook.xml +1 -0
- oxlsx-0.1.0/samples/unzipped/xl/worksheets/sheet1.xml +1 -0
- oxlsx-0.1.0/skills-lock.json +23 -0
- oxlsx-0.1.0/src/comments.rs +120 -0
- oxlsx-0.1.0/src/coords.rs +153 -0
- oxlsx-0.1.0/src/defined_names.rs +837 -0
- oxlsx-0.1.0/src/error.rs +32 -0
- oxlsx-0.1.0/src/hyperlink.rs +71 -0
- oxlsx-0.1.0/src/lib.rs +27 -0
- oxlsx-0.1.0/src/main.rs +3 -0
- oxlsx-0.1.0/src/python.rs +1511 -0
- oxlsx-0.1.0/src/reader.rs +1909 -0
- oxlsx-0.1.0/src/readonly.rs +560 -0
- oxlsx-0.1.0/src/shared_strings.rs +132 -0
- oxlsx-0.1.0/src/sheet_rels.rs +730 -0
- oxlsx-0.1.0/src/styles.rs +384 -0
- oxlsx-0.1.0/src/table.rs +541 -0
- oxlsx-0.1.0/src/workbook_rels.rs +161 -0
- oxlsx-0.1.0/src/writer.rs +1971 -0
- oxlsx-0.1.0/src/xml.rs +19 -0
- oxlsx-0.1.0/tests/integration_test.rs +2651 -0
- oxlsx-0.1.0/tests/test_python.py +1146 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust-coding
|
|
3
|
+
description: Rust coding conventions expert covering naming, formatting, comments, clippy, rustfmt, lints, code style, best practices, and idiomatic patterns.
|
|
4
|
+
metadata:
|
|
5
|
+
triggers:
|
|
6
|
+
- coding convention
|
|
7
|
+
- naming
|
|
8
|
+
- formatting
|
|
9
|
+
- clippy
|
|
10
|
+
- rustfmt
|
|
11
|
+
- lint
|
|
12
|
+
- code style
|
|
13
|
+
- best practice
|
|
14
|
+
- idiomatic
|
|
15
|
+
- code review
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## Naming Conventions (Rust-Specific)
|
|
20
|
+
|
|
21
|
+
| Rule | Correct | Incorrect |
|
|
22
|
+
|------|---------|-----------|
|
|
23
|
+
| No `get_` prefix for methods | `fn name(&self)` | `fn get_name(&self)` |
|
|
24
|
+
| Iterator methods | `iter()` / `iter_mut()` / `into_iter()` | `get_iter()` |
|
|
25
|
+
| Conversion naming | `as_` (cheap), `to_` (expensive), `into_` (ownership) | Mixed usage |
|
|
26
|
+
| `static` variables uppercase | `static CONFIG: Config` | `static config: Config` |
|
|
27
|
+
| `const` variables | `const BUFFER_SIZE: usize = 1024` | No restriction |
|
|
28
|
+
|
|
29
|
+
### General Naming
|
|
30
|
+
|
|
31
|
+
```rust
|
|
32
|
+
// Variables and functions: snake_case
|
|
33
|
+
let max_connections = 100;
|
|
34
|
+
fn process_data() { ... }
|
|
35
|
+
|
|
36
|
+
// Types and traits: CamelCase
|
|
37
|
+
struct UserSession;
|
|
38
|
+
trait Cacheable {}
|
|
39
|
+
|
|
40
|
+
// Constants: SCREAMING_SNAKE_CASE
|
|
41
|
+
const MAX_CONNECTIONS: usize = 100;
|
|
42
|
+
static CONFIG: once_cell::sync::Lazy<Config> = ...
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## Solution Patterns
|
|
47
|
+
|
|
48
|
+
### Pattern 1: Conversion Methods
|
|
49
|
+
|
|
50
|
+
```rust
|
|
51
|
+
impl Buffer {
|
|
52
|
+
// as_ - cheap, view conversion
|
|
53
|
+
pub fn as_slice(&self) -> &[u8] {
|
|
54
|
+
&self.data
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// to_ - expensive, allocating conversion
|
|
58
|
+
pub fn to_vec(&self) -> Vec<u8> {
|
|
59
|
+
self.data.clone()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// into_ - consuming, ownership transfer
|
|
63
|
+
pub fn into_vec(self) -> Vec<u8> {
|
|
64
|
+
self.data
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Pattern 2: Newtype Pattern
|
|
70
|
+
|
|
71
|
+
```rust
|
|
72
|
+
// ✅ Domain semantics with newtypes
|
|
73
|
+
struct Email(String);
|
|
74
|
+
struct UserId(u64);
|
|
75
|
+
struct Meters(f64);
|
|
76
|
+
|
|
77
|
+
impl Email {
|
|
78
|
+
pub fn new(s: impl Into<String>) -> Result<Self, EmailError> {
|
|
79
|
+
let email = s.into();
|
|
80
|
+
if email.contains('@') {
|
|
81
|
+
Ok(Self(email))
|
|
82
|
+
} else {
|
|
83
|
+
Err(EmailError::Invalid)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Pattern 3: Error Handling
|
|
90
|
+
|
|
91
|
+
```rust
|
|
92
|
+
// ✅ Good: propagate errors
|
|
93
|
+
fn read_config() -> Result<Config, ConfigError> {
|
|
94
|
+
let content = std::fs::read_to_string("config.toml")
|
|
95
|
+
.map_err(ConfigError::from)?;
|
|
96
|
+
toml::from_str(&content)
|
|
97
|
+
.map_err(ConfigError::Parse)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ❌ Avoid: panic in library code
|
|
101
|
+
fn read_config() -> Config {
|
|
102
|
+
std::fs::read_to_string("config.toml").unwrap() // panic!
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ✅ Use expect when invariant guaranteed
|
|
106
|
+
fn get_user(&self) -> &User {
|
|
107
|
+
self.user.as_ref()
|
|
108
|
+
.expect("user always initialized in constructor")
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Pattern 4: String Handling
|
|
113
|
+
|
|
114
|
+
```rust
|
|
115
|
+
// ✅ Accept &str in APIs
|
|
116
|
+
fn greet(name: &str) {
|
|
117
|
+
println!("Hello, {}", name);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ✅ Use Cow when might need owned
|
|
121
|
+
use std::borrow::Cow;
|
|
122
|
+
|
|
123
|
+
fn process(input: &str) -> Cow<str> {
|
|
124
|
+
if input.contains("special") {
|
|
125
|
+
Cow::Owned(input.replace("special", "normal"))
|
|
126
|
+
} else {
|
|
127
|
+
Cow::Borrowed(input)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ✅ Pre-allocate when size known
|
|
132
|
+
let mut s = String::with_capacity(100);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
## Data Type Guidelines
|
|
137
|
+
|
|
138
|
+
| Rule | Description | Example |
|
|
139
|
+
|------|-------------|---------|
|
|
140
|
+
| Use newtype | Domain semantics | `struct Email(String)` |
|
|
141
|
+
| Use slice patterns | Pattern matching | `if let [first, .., last] = slice` |
|
|
142
|
+
| Pre-allocate | Avoid reallocations | `Vec::with_capacity()` |
|
|
143
|
+
| Avoid Vec abuse | Fixed size → array | `let arr: [u8; 256]` |
|
|
144
|
+
|
|
145
|
+
### String Guidelines
|
|
146
|
+
|
|
147
|
+
| Rule | Description |
|
|
148
|
+
|------|-------------|
|
|
149
|
+
| ASCII data use `bytes()` | `s.bytes()` faster than `s.chars()` |
|
|
150
|
+
| Might modify → `Cow<str>` | Borrow or owned |
|
|
151
|
+
| Use `format!` for concat | Better than `+` operator |
|
|
152
|
+
| Avoid nested `contains()` | O(n*m) complexity |
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
## Error Handling Guidelines
|
|
156
|
+
|
|
157
|
+
| Rule | Description |
|
|
158
|
+
|------|-------------|
|
|
159
|
+
| Use `?` to propagate | Don't use `try!()` macro |
|
|
160
|
+
| `expect()` over `unwrap()` | When value guaranteed |
|
|
161
|
+
| Use `assert!` for invariants | At function entry |
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
## Memory and Lifetimes
|
|
165
|
+
|
|
166
|
+
| Rule | Description |
|
|
167
|
+
|------|-------------|
|
|
168
|
+
| Meaningful lifetime names | `'src`, `'ctx` not just `'a` |
|
|
169
|
+
| `RefCell` use `try_borrow` | Avoid panics |
|
|
170
|
+
| Use shadowing for conversions | `let x = x.parse()?` |
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
## Concurrency Guidelines
|
|
174
|
+
|
|
175
|
+
| Rule | Description |
|
|
176
|
+
|------|-------------|
|
|
177
|
+
| Define lock ordering | Prevent deadlocks |
|
|
178
|
+
| Atomics for primitives | Not `Mutex<bool>` |
|
|
179
|
+
| Choose memory ordering carefully | Relaxed/Acquire/Release/SeqCst |
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
## Async Guidelines
|
|
183
|
+
|
|
184
|
+
| Rule | Description |
|
|
185
|
+
|------|-------------|
|
|
186
|
+
| CPU-bound → sync | Async for I/O |
|
|
187
|
+
| Don't hold locks across await | Use scoped guards |
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
## Macro Guidelines
|
|
191
|
+
|
|
192
|
+
| Rule | Description |
|
|
193
|
+
|------|-------------|
|
|
194
|
+
| Avoid macros (unless necessary) | Prefer functions/generics |
|
|
195
|
+
| Macro input like Rust | Readability first |
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
## Deprecated Patterns → Modern
|
|
199
|
+
|
|
200
|
+
| Deprecated | Modern | Version |
|
|
201
|
+
|-----------|---------|---------|
|
|
202
|
+
| `lazy_static!` | `std::sync::OnceLock` | 1.70 |
|
|
203
|
+
| `once_cell::Lazy` | `std::sync::LazyLock` | 1.80 |
|
|
204
|
+
| `std::sync::mpsc` | `crossbeam::channel` | - |
|
|
205
|
+
| `std::sync::Mutex` | `parking_lot::Mutex` | - |
|
|
206
|
+
| `failure`/`error-chain` | `thiserror`/`anyhow` | - |
|
|
207
|
+
| `try!()` | `?` operator | 2018 |
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
## Clippy Configuration
|
|
211
|
+
|
|
212
|
+
```toml
|
|
213
|
+
[package]
|
|
214
|
+
edition = "2024"
|
|
215
|
+
rust-version = "1.85"
|
|
216
|
+
|
|
217
|
+
[lints.rust]
|
|
218
|
+
unsafe_code = "warn"
|
|
219
|
+
|
|
220
|
+
[lints.clippy]
|
|
221
|
+
all = "warn"
|
|
222
|
+
pedantic = "warn"
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Common Clippy Lints
|
|
226
|
+
|
|
227
|
+
| Lint | Description |
|
|
228
|
+
|------|-------------|
|
|
229
|
+
| `clippy::all` | Enable all warnings |
|
|
230
|
+
| `clippy::pedantic` | Stricter checks |
|
|
231
|
+
| `clippy::unwrap_used` | Avoid unwrap |
|
|
232
|
+
| `clippy::expect_used` | Prefer expect |
|
|
233
|
+
| `clippy::clone_on_ref_ptr` | Avoid cloning Arc |
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
## Formatting (rustfmt)
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# Use default config
|
|
240
|
+
rustfmt src/lib.rs
|
|
241
|
+
|
|
242
|
+
# Check formatting
|
|
243
|
+
rustfmt --check src/lib.rs
|
|
244
|
+
|
|
245
|
+
# Config file: .rustfmt.toml
|
|
246
|
+
max_width = 100
|
|
247
|
+
tab_spaces = 4
|
|
248
|
+
edition = "2024"
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
## Documentation Guidelines
|
|
253
|
+
|
|
254
|
+
```rust
|
|
255
|
+
/// Module documentation
|
|
256
|
+
//! This module handles user authentication...
|
|
257
|
+
|
|
258
|
+
/// Struct documentation
|
|
259
|
+
///
|
|
260
|
+
/// # Examples
|
|
261
|
+
/// ```
|
|
262
|
+
/// let user = User::new("name");
|
|
263
|
+
/// ```
|
|
264
|
+
pub struct User { ... }
|
|
265
|
+
|
|
266
|
+
/// Method documentation
|
|
267
|
+
///
|
|
268
|
+
/// # Arguments
|
|
269
|
+
///
|
|
270
|
+
/// * `name` - User name
|
|
271
|
+
///
|
|
272
|
+
/// # Returns
|
|
273
|
+
///
|
|
274
|
+
/// Initialized user instance
|
|
275
|
+
///
|
|
276
|
+
/// # Panics
|
|
277
|
+
///
|
|
278
|
+
/// Panics when name is empty
|
|
279
|
+
pub fn new(name: &str) -> Self { ... }
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
## Workflow
|
|
284
|
+
|
|
285
|
+
### Step 1: Name Things Properly
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
Choosing a name?
|
|
289
|
+
→ Function/variable? snake_case
|
|
290
|
+
→ Type/trait? CamelCase
|
|
291
|
+
→ Constant? SCREAMING_SNAKE_CASE
|
|
292
|
+
→ Conversion method?
|
|
293
|
+
- Cheap view? as_foo()
|
|
294
|
+
- Expensive? to_foo()
|
|
295
|
+
- Consuming? into_foo()
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Step 2: Format Code
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
# Run rustfmt
|
|
302
|
+
cargo fmt
|
|
303
|
+
|
|
304
|
+
# Check formatting in CI
|
|
305
|
+
cargo fmt --check
|
|
306
|
+
|
|
307
|
+
# Fix clippy warnings
|
|
308
|
+
cargo clippy --fix
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Step 3: Review Idioms
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
Check:
|
|
315
|
+
→ No unnecessary clone()
|
|
316
|
+
→ Use ? not unwrap()
|
|
317
|
+
→ &str in function parameters
|
|
318
|
+
→ Iterator methods not index loops
|
|
319
|
+
→ Meaningful error types
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
## Quick Reference
|
|
324
|
+
|
|
325
|
+
```
|
|
326
|
+
Naming: snake_case (fn/var), CamelCase (type), SCREAMING_SNAKE_CASE (const)
|
|
327
|
+
Format: rustfmt (just use it)
|
|
328
|
+
Docs: /// for public items, //! for module docs
|
|
329
|
+
Lint: #![warn(clippy::all)]
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
## Review Checklist
|
|
334
|
+
|
|
335
|
+
When reviewing code:
|
|
336
|
+
|
|
337
|
+
- [ ] Naming follows Rust conventions
|
|
338
|
+
- [ ] Using `?` instead of `unwrap()`
|
|
339
|
+
- [ ] Avoiding unnecessary `clone()`
|
|
340
|
+
- [ ] `unsafe` blocks have SAFETY comments
|
|
341
|
+
- [ ] Public APIs have doc comments
|
|
342
|
+
- [ ] Ran `cargo clippy`
|
|
343
|
+
- [ ] Ran `cargo fmt`
|
|
344
|
+
- [ ] No `get_` prefix on accessor methods
|
|
345
|
+
- [ ] Conversion methods named correctly (as/to/into)
|
|
346
|
+
- [ ] String parameters use `&str` when possible
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
## Verification Commands
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
# Format check
|
|
353
|
+
cargo fmt --check
|
|
354
|
+
|
|
355
|
+
# Lint check
|
|
356
|
+
cargo clippy -- -D warnings
|
|
357
|
+
|
|
358
|
+
# Documentation check
|
|
359
|
+
cargo doc --no-deps --open
|
|
360
|
+
|
|
361
|
+
# Run tests
|
|
362
|
+
cargo test
|
|
363
|
+
|
|
364
|
+
# Check naming conventions
|
|
365
|
+
cargo clippy -- -W clippy::wrong_self_convention
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
## Common Pitfalls
|
|
370
|
+
|
|
371
|
+
### 1. Wrong Method Naming
|
|
372
|
+
|
|
373
|
+
**Symptom**: Clippy warning `wrong_self_convention`
|
|
374
|
+
|
|
375
|
+
```rust
|
|
376
|
+
// ❌ Bad: unnecessary get_ prefix
|
|
377
|
+
impl User {
|
|
378
|
+
fn get_name(&self) -> &str { &self.name }
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// ✅ Good: direct accessor
|
|
382
|
+
impl User {
|
|
383
|
+
fn name(&self) -> &str { &self.name }
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### 2. String Type Misuse
|
|
388
|
+
|
|
389
|
+
**Symptom**: Unnecessary allocations
|
|
390
|
+
|
|
391
|
+
```rust
|
|
392
|
+
// ❌ Bad: forces allocation
|
|
393
|
+
fn greet(name: String) {
|
|
394
|
+
println!("Hello, {}", name);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// ✅ Good: accepts borrowed or owned
|
|
398
|
+
fn greet(name: &str) {
|
|
399
|
+
println!("Hello, {}", name);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Both work now:
|
|
403
|
+
greet("Alice"); // &str
|
|
404
|
+
greet(&owned_string); // &String → &str
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 3. Index Loops
|
|
408
|
+
|
|
409
|
+
**Symptom**: Less idiomatic, error-prone
|
|
410
|
+
|
|
411
|
+
```rust
|
|
412
|
+
// ❌ Bad: manual indexing
|
|
413
|
+
for i in 0..items.len() {
|
|
414
|
+
println!("{}: {}", i, items[i]);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// ✅ Good: iterator
|
|
418
|
+
for item in &items {
|
|
419
|
+
println!("{}", item);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// ✅ Good: with index
|
|
423
|
+
for (i, item) in items.iter().enumerate() {
|
|
424
|
+
println!("{}: {}", i, item);
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
## Related Skills
|
|
430
|
+
|
|
431
|
+
- **rust-anti-pattern** - What not to do
|
|
432
|
+
- **rust-error** - Error handling patterns
|
|
433
|
+
- **rust-performance** - Performance idioms
|
|
434
|
+
- **rust-async** - Async conventions
|
|
435
|
+
- **rust-unsafe** - SAFETY comment style
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
## Localized Reference
|
|
439
|
+
|
|
440
|
+
- **Chinese version**: [SKILL_ZH.md](./SKILL_ZH.md) - 完整中文版本,包含所有内容
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust-coding
|
|
3
|
+
description: "Rust coding standards skill for API ergonomics, module design, naming conventions, testability, and maintainability in production codebases."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rust Coding Standards Skill
|
|
7
|
+
|
|
8
|
+
## Core Question
|
|
9
|
+
|
|
10
|
+
**How do we keep Rust code easy to change, easy to review, and hard to misuse?**
|
|
11
|
+
|
|
12
|
+
## Coding Principles
|
|
13
|
+
|
|
14
|
+
- Design APIs to make invalid states hard to represent.
|
|
15
|
+
- Prefer small, composable functions over large multi-purpose routines.
|
|
16
|
+
- Keep ownership and error behavior explicit at boundaries.
|
|
17
|
+
- Optimize readability first, then optimize hot paths with evidence.
|
|
18
|
+
|
|
19
|
+
## Project Structure Guidelines
|
|
20
|
+
|
|
21
|
+
Recommended layering:
|
|
22
|
+
- `domain`: core business types and invariants.
|
|
23
|
+
- `service`: use-case orchestration.
|
|
24
|
+
- `infra`: external integrations (DB, HTTP, cache).
|
|
25
|
+
- `interface`: handler/controller/CLI entry points.
|
|
26
|
+
|
|
27
|
+
Module rules:
|
|
28
|
+
- Avoid giant `mod.rs` files; split by behavior.
|
|
29
|
+
- Keep public surface minimal (`pub(crate)` by default).
|
|
30
|
+
- Re-export intentionally to shape stable APIs.
|
|
31
|
+
|
|
32
|
+
## API Ergonomics Patterns
|
|
33
|
+
|
|
34
|
+
- Accept `&str` instead of `String` when ownership is not required.
|
|
35
|
+
- Accept slices (`&[T]`) instead of `Vec<T>` in read-only APIs.
|
|
36
|
+
- Use builder patterns for complex constructors.
|
|
37
|
+
- Prefer domain-specific types over primitive obsession.
|
|
38
|
+
|
|
39
|
+
```rust
|
|
40
|
+
pub struct UserId(String);
|
|
41
|
+
|
|
42
|
+
impl UserId {
|
|
43
|
+
pub fn parse(value: &str) -> Result<Self, &'static str> {
|
|
44
|
+
if value.is_empty() { return Err("empty user id"); }
|
|
45
|
+
Ok(Self(value.to_owned()))
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Error and Logging Conventions
|
|
51
|
+
|
|
52
|
+
- Return typed errors in reusable modules.
|
|
53
|
+
- Add context at boundary crossings (I/O, parsing, RPC).
|
|
54
|
+
- Log once at boundary layers; avoid duplicate logs in deep internals.
|
|
55
|
+
|
|
56
|
+
## Review Checklist
|
|
57
|
+
|
|
58
|
+
- [ ] Public API contracts are clear and minimal.
|
|
59
|
+
- [ ] Naming follows domain language and Rust conventions.
|
|
60
|
+
- [ ] Functions have single, testable responsibilities.
|
|
61
|
+
- [ ] Errors include actionable context.
|
|
62
|
+
- [ ] Tests cover critical behavior and edge cases.
|
|
63
|
+
|
|
64
|
+
## Common Pitfalls
|
|
65
|
+
|
|
66
|
+
- Excessive `.clone()` to bypass ownership design.
|
|
67
|
+
- Large enums/modules with mixed responsibilities.
|
|
68
|
+
- `unwrap` usage in production paths.
|
|
69
|
+
- Hidden side effects in “helper” utilities.
|
|
70
|
+
|
|
71
|
+
## Verification Commands
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
cargo fmt --check
|
|
75
|
+
cargo clippy -- -D warnings
|
|
76
|
+
cargo test
|
|
77
|
+
cargo doc --no-deps
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Related Skills
|
|
81
|
+
|
|
82
|
+
- `rust-anti-pattern`
|
|
83
|
+
- `rust-error`
|
|
84
|
+
- `rust-type-driven`
|
|
85
|
+
|
|
86
|
+
## Localized Reference
|
|
87
|
+
|
|
88
|
+
- Original Chinese version is preserved in `SKILL_ZH.md`.
|