rlm-rs
zircote/rlm-rs/.github/copilot-instructions.md
This document provides context for GitHub Copilot when working with this Rust project. This is a Rust crate using modern tooling: - Rust: 1.95+ (2024 edition) - Build System: Cargo - Linting: clippy with pedantic and nursery lints - Formatting: rustfmt - Testing: Built-in test framework + proptest - Supply Chain Security: cargo-deny Use Result types instead of panicking: Use thiserror for custom error types: Provide explicit return types for public functions: Use doc comments with examples: rust /// use…
Copilot instructions57 starsChanged 9 months ago
# GitHub Copilot Instructions
This document provides context for GitHub Copilot when working with this Rust project.
## Project Context
This is a Rust crate using modern tooling:
- **Rust**: 1.95+ (2024 edition)
- **Build System**: Cargo
- **Linting**: clippy with pedantic and nursery lints
- **Formatting**: rustfmt
- **Testing**: Built-in test framework + proptest
- **Supply Chain Security**: cargo-deny
## Code Generation Guidelines
### Error Handling
Use `Result` types instead of panicking:
```rust
// Good - Returns Result
pub fn parse_value(input: &str) -> Result<i64, ParseError> {
input.parse().map_err(|e| ParseError::InvalidFormat(e))
}
// Avoid - Panics on failure
pub fn parse_value(input: &str) -> i64 {
input.parse().unwrap() // Never do this
}
```
Use `thiserror` for custom error types:
```rust
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("invalid input: {0}")]
InvalidInput(String),
#[error("operation failed: {operation}")]
OperationFailed { operation: String },
#[error(transparent)]
Io(#[from] std::io::Error),
}
```
### Type Annotations
Provide explicit return types for public functions:
```rust
// Good - explicit return type
pub fn process_data(items: &[String]) -> Vec<ProcessedItem> {
// implementation
}
// Avoid for public APIs
pub fn process_data(items: &[String]) -> impl Iterator<Item = ProcessedItem> {
// implementation
}
```
### Documentation
Use doc comments with examples:
```rust
/// Processes a list of items according to the given configuration.
///
/// # Arguments
///
/// * `items` - The items to process.
/// * `config` - Configuration options for processing.
///
/// # Returns
///
/// A vector of processed items.
///
/// # Errors
///
/// Returns [`Error::InvalidInput`] if any item is invalid.
///
/// # Examples
///
/// ```rust
/// use rlm_rs::{process, Config};
///
/// let items = vec!["a", "b", "c"];
/// let config = Config::default();
/// let result = process(&items, &config)?;
/// # Ok::<(), rlm_rs::Error>(())
/// ```
pub fn process(items: &[&str], config: &Config) -> Result<Vec<Item>> {
// implementation
}
```
### Ownership and Borrowing
Prefer borrowing over ownership when possible:
```rust
// Good - borrows the slice
pub fn sum_values(values: &[i64]) -> i64 {
values.iter().sum()
}
// Avoid - takes ownership unnecessarily
pub fn sum_values(values: Vec<i64>) -> i64 {
values.iter().sum()
}
```
Use `Cow` for efficient string handling:
```rust
use std::borrow::Cow;
pub fn normalize_name(name: &str) -> Cow<'_, str> {
if name.contains(' ') {
Cow::Owned(name.replace(' ', "_"))
} else {
Cow::Borrowed(name)
}
}
```
### Structs and Enums
Use builder pattern for complex structs:
```rust
#[derive(Debug, Clone, Default)]
pub struct Config {
pub timeout: Duration,
pub retries: u32,
pub verbose: bool,
}
impl Config {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
#[must_use]
pub fn with_retries(mut self, retries: u32) -> Self {
self.retries = retries;
self
}
}
```
### Testing
Write comprehensive unit tests:
```rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add_positive_numbers() {
assert_eq!(add(2, 3), 5);
}
#[test]
fn test_divide_by_zero_returns_error() {
let result = divide(10, 0);
assert!(matches!(result, Err(Error::DivisionByZero)));
}
}
```
Use proptest for property-based testing:
```rust
use proptest::prelude::*;
proptest! {
#[test]
fn add_is_commutative(a in any::<i64>(), b in any::<i64>()) {
prop_assert_eq!(add(a, b), add(b, a));
}
}
```
### Async Code
Use async/await with tokio:
```rust
pub async fn fetch_data(url: &str) -> Result<Data> {
let response = reqwest::get(url).await?;
let data = response.json().await?;
Ok(data)
}
```
## Common Patterns
### Iterator Chains
```rust
let result: Vec<_> = items
.iter()
.filter(|item| item.is_valid())
.map(|item| item.transform())
.collect();
```
### Option and Result Combinators
```rust
// Option chaining
let value = config
.get_setting("key")
.and_then(|s| s.parse().ok())
.unwrap_or_default();
// Result chaining with ?
fn process() -> Result<Output> {
let data = load_data()?;
let parsed = parse_data(&data)?;
let result = transform(parsed)?;
Ok(result)
}
```
### Const Functions
Prefer `const fn` for compile-time evaluation:
```rust
#[must_use]
pub const fn new() -> Self {
Self { value: 0 }
}
```
## File Locations
- Source code: `src/`
- Library entry: `src/lib.rs`
- Binary entry: `src/main.rs`
- Integration tests: `tests/`
- Benchmarks: `benches/` (with criterion)
## Commands
```bash
cargo build # Build
cargo test # Run tests
cargo clippy # Lint
cargo fmt # Format
cargo doc --open # Generate and view docs
cargo deny check # Check supply chain
```
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
Posts are public.Sign in to post
No one has posted yet. Be the first.

