rust-coding-guidelines
Rust and GPUI coding standards. MUST LOAD before writing any Rust code. Covers error handling, naming conventions, async patterns, file organization, and GPUI-specific rules. This skill is MANDATORY for all Rust work in this project.
Installation
Suivez les instructions du dépôt pour votre agent. Consultez les fichiers et dépendances avant l’installation.
Voir la source ↗GuidesInstructions
Rust Coding Guidelines
IMPORTANT: This skill contains mandatory coding rules for this project. Violations will cause code review failures.
Core Principles
- Prioritize correctness and clarity - Speed/efficiency are secondary unless specified
- Avoid creative additions - Unless explicitly requested
- Prefer existing files - Unless creating a new logical component
- Comments explain "why", not "what" - No organizational/summary comments
Error Handling (CRITICAL)
NEVER use unwrap()
// WRONG
let value = option.unwrap();
let result = operation().unwrap();
// CORRECT - propagate with ?
let value = option.ok_or_else(|| anyhow::anyhow!("Missing value"))?;
let result = operation()?;
// CORRECT - explicit handling
match option {
Some(value) => { /* use value */ }
None => { /* handle missing */ }
}
NEVER silently discard errors
// WRONG - silently discards error
let _ = client.request(url).await?;
// CORRECT - propagate
client.request(url).await?;
// CORRECT - log but continue
operation().log_err();
// CORRECT - explicit handling
if let Err(e) = operation() {
eprintln!("Operation failed: {}", e);
}
ALWAYS propagate errors to UI
fn save_file(&mut self, cx: &mut Context<Self>) {
cx.spawn(async move |this, cx| {
match write_file(path, data).await {
Ok(()) => {
this.update(&mut *cx, |view, cx| {
view.status = "Saved successfully".into();
cx.notify();
})?;
}
Err(e) => {
this.update(&mut *cx, |view, cx| {
view.error = Some(format!("Save failed: {}", e));
cx.notify();
})?;
}
}
Ok(())
}).detach_and_log_err(cx);
}
Indexing Safety
Be careful with indexing operations - they may panic if indexes are out of bounds.
// WRONG - may panic
let item = items[index];
// CORRECT - safe access
let item = items.get(index).ok_or_else(|| anyhow::anyhow!("Index out of bounds"))?;
Variable Naming
Use full words (NO abbreviations)
// WRONG
let q = VecDeque::new();
let cnt = 0;
let btn = Button::new();
// CORRECT
let queue = VecDeque::new();
let count = 0;
let button = Button::new();
Async Patterns
Variable Shadowing for Clones
Use variable shadowing to scope clones in async contexts:
// CORRECT pattern
executor.spawn({
let task_ran = task_ran.clone();
async move {
*task_ran.borrow_mut() = true;
}
});
File Organization
NEVER create mod.rs files
// WRONG
src/
components/
mod.rs // Don't do this
button.rs
// CORRECT
src/
components.rs // Module file
components/
button.rs
Library Root Paths
For crates, specify library root in Cargo.toml:
[lib]
path = "src/my_lib.rs" # Instead of default lib.rs
GPUI-Specific Rules
Context Types
-
App- root context, access to global state -
Context<T>- provided when updatingEntity<T>, dereferences toApp -
AsyncApp/AsyncWindowContext- fromcx.spawn, can be held across await points
Window Parameter
Window comes before cx when present:
impl Render for MyView {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
// window first, cx second
}
}
Entity Operations
// Read
let view = entity.read(cx);
// Update (use inner cx!)
entity.update(cx, |view, inner_cx| {
view.count += 1;
inner_cx.notify(); // Use inner_cx, NOT outer cx!
});
// NEVER update while already updating
entity.update(cx, |view, cx| {
entity.update(cx, |_, _| {}); // PANIC!
});
Testing Timers
In GPUI tests, use GPUI executor timers, NOT smol::Timer:
// WRONG - may cause "nothing left to run"
smol::Timer::after(duration).await;
// CORRECT
cx.background_executor().timer(duration).await;
// or
cx.background_executor.timer(duration).await; // in TestAppContext
Event Handlers
// Using cx.listener for callbacks
.on_click(cx.listener(|this: &mut Self, event, window, cx| {
// this: &mut Self
// event: click event
// window: &mut Window
// cx: &mut Context<Self>
}))
Notify After State Changes
fn update_state(&mut self, cx: &mut Context<Self>) {
self.data = new_data;
cx.notify(); // Required for UI update
}
EventEmitter
// Declare event type
impl EventEmitter<MyEvent> for MyView {}
// Emit in handler
cx.emit(MyEvent::ValueChanged(value));
Subscriptions
Store Subscription in struct fields - they auto-cancel when dropped:
struct Parent {
child: Entity<Child>,
_subscription: Subscription, // Keep alive
}
Project-Specific Rules
dbg!() and todo!() are DENIED
This project has Clippy rules that deny dbg!() and todo!() macros.
// WRONG - will fail clippy
dbg!(value);
todo!();
// Use proper logging or error handling instead
Workspace Dependencies
All dependencies must be declared in workspace Cargo.toml, sub-crates use .workspace = true:
# In sub-crate Cargo.toml
[dependencies]
gpui.workspace = true
Quick Reference Checklist
Before submitting code:
- No
unwrap()calls - No
let _ =on fallible operations - No
dbg!()ortodo!() - Full variable names (no abbreviations)
- No
mod.rsfiles -
cx.notify()after state changes - Errors propagate to UI
- GPUI timers in tests (not smol)
- Subscriptions stored in struct fields
- Using inner
cxin entity update closures
References
- Project
.rulefile - Zed GEMINI.md
- Rust API Guidelines
Exemples
Consultez les exemples du dépôt source.
Voir la source ↗Historique source
- Date d’indexation
- 2026-03-11
- Mise à jour de l’index
- 2026-03-11
- Branch
- main
Les dates concernent ce répertoire. Consultez le dépôt pour l’historique du code.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!