Claude Code Plugins

Community-maintained marketplace

Feedback

rust-ms-libraries

@vanyastaff/paramdef
0
0

Microsoft Pragmatic Rust Library Guidelines. Use when designing library crates, public APIs, managing dependencies, or creating reusable components.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name rust-ms-libraries
description Microsoft Pragmatic Rust Library Guidelines. Use when designing library crates, public APIs, managing dependencies, or creating reusable components.
allowed-tools Read, Write, Edit, Bash, Grep, Glob

Microsoft Pragmatic Rust - Library Guidelines

Guidelines for building high-quality, reusable Rust libraries.

Crate Structure

Flat vs Nested Modules

// GOOD - flat structure for small libraries
// src/lib.rs
mod error;
mod types;
mod client;

pub use error::Error;
pub use types::{Config, Options};
pub use client::Client;

// GOOD - nested for large libraries
// src/lib.rs
pub mod http;
pub mod storage;
pub mod auth;

// Re-export common items at root
pub use http::Client;
pub use storage::Store;

Prelude Pattern

// For libraries with many types
// src/prelude.rs
pub use crate::error::{Error, Result};
pub use crate::types::{Config, Options, Status};
pub use crate::traits::{Execute, Validate};

// Users can import everything
use my_library::prelude::*;

API Design

Accept Generics, Return Concrete

// GOOD - flexible input, concrete output
pub fn process(input: impl AsRef<str>) -> String {
    let s = input.as_ref();
    s.to_uppercase()
}

// Can be called with &str, String, Cow<str>, etc.
process("hello");
process(String::from("hello"));

Use Into for Ownership Transfer

impl Client {
    // Accept anything convertible to String
    pub fn set_name(&mut self, name: impl Into<String>) {
        self.name = name.into();
    }
}

// Both work
client.set_name("name");
client.set_name(string_var);

Builder Pattern for Complex Construction

#[derive(Default)]
pub struct ClientBuilder {
    host: Option<String>,
    port: Option<u16>,
    timeout: Option<Duration>,
}

impl ClientBuilder {
    pub fn new() -> Self {
        Self::default()
    }
    
    pub fn host(mut self, host: impl Into<String>) -> Self {
        self.host = Some(host.into());
        self
    }
    
    pub fn port(mut self, port: u16) -> Self {
        self.port = Some(port);
        self
    }
    
    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = Some(timeout);
        self
    }
    
    pub fn build(self) -> Result<Client, BuildError> {
        Ok(Client {
            host: self.host.ok_or(BuildError::MissingHost)?,
            port: self.port.unwrap_or(8080),
            timeout: self.timeout.unwrap_or(Duration::from_secs(30)),
        })
    }
}

Sealed Traits for Extension Prevention

mod private {
    pub trait Sealed {}
}

/// A trait that cannot be implemented outside this crate.
pub trait MyTrait: private::Sealed {
    fn method(&self);
}

// Implement Sealed for allowed types
impl private::Sealed for MyType {}
impl MyTrait for MyType {
    fn method(&self) { ... }
}

Error Design

Library-Specific Error Types

use thiserror::Error;

/// Errors that can occur in this library.
#[derive(Debug, Error)]
#[non_exhaustive]  // Allow adding variants
pub enum Error {
    #[error("connection failed: {0}")]
    Connection(String),
    
    #[error("invalid configuration: {0}")]
    Config(String),
    
    #[error("operation timed out after {duration:?}")]
    Timeout { duration: Duration },
    
    #[error(transparent)]
    Io(#[from] std::io::Error),
}

/// Result type alias for convenience
pub type Result<T> = std::result::Result<T, Error>;

Don't Expose Internal Errors

// BAD - leaks internal dependency
#[derive(Error)]
pub enum Error {
    #[error(transparent)]
    Database(#[from] sqlx::Error),  // Exposes sqlx
}

// GOOD - wrap internal errors
#[derive(Error)]
pub enum Error {
    #[error("database error: {0}")]
    Database(String),
}

impl From<sqlx::Error> for Error {
    fn from(e: sqlx::Error) -> Self {
        Error::Database(e.to_string())
    }
}

Dependency Management

Minimal Dependencies

# Only depend on what you need
[dependencies]
serde = { version = "1.0", optional = true }

[features]
default = []
serde = ["dep:serde"]

Re-export Dependencies Users Need

// If users need types from your dependencies, re-export them
pub use bytes::Bytes;
pub use http::StatusCode;

Version Policy

# Use caret requirements for flexibility
serde = "1.0"        # ^1.0 - allows 1.x updates
tokio = "1"          # ^1 - allows 1.x updates

# Pin exact versions only when necessary
some-crate = "=1.2.3"

Resilience

Avoid Global State

// BAD - global mutable state
static COUNTER: AtomicU64 = AtomicU64::new(0);

// GOOD - instance state
pub struct Counter {
    value: AtomicU64,
}

impl Counter {
    pub fn new() -> Self {
        Self { value: AtomicU64::new(0) }
    }
    
    pub fn increment(&self) -> u64 {
        self.value.fetch_add(1, Ordering::SeqCst)
    }
}

Avoid Thread-Local Storage

// BAD - hidden state
thread_local! {
    static CACHE: RefCell<HashMap<String, Value>> = RefCell::new(HashMap::new());
}

// GOOD - explicit state
pub struct Cache {
    data: RwLock<HashMap<String, Value>>,
}

Make Types Send + Sync When Possible

// Ensure thread safety
pub struct Client {
    inner: Arc<ClientInner>,  // Arc for shared ownership
}

// Verify at compile time
static_assertions::assert_impl_all!(Client: Send, Sync);

Documentation

Crate-Level Docs

//! # My Library
//!
//! A brief description of what this library does.
//!
//! ## Quick Start
//!
//! ```rust
//! use my_library::Client;
//!
//! let client = Client::builder()
//!     .host("localhost")
//!     .build()?;
//!
//! client.connect().await?;
//! ```
//!
//! ## Features
//!
//! - Feature 1
//! - Feature 2
//!
//! ## Feature Flags
//!
//! - `serde`: Enable serialization support

Document All Public Items

Every public item needs:

  • Brief description
  • Examples (that compile and run)
  • Error conditions for fallible functions
  • Panic conditions if applicable

Versioning

Semantic Versioning

  • MAJOR: Breaking API changes
  • MINOR: New features, backward compatible
  • PATCH: Bug fixes, backward compatible

Breaking Changes

// Use #[deprecated] before removing
#[deprecated(since = "0.5.0", note = "use new_function instead")]
pub fn old_function() { ... }

// Use #[doc(hidden)] for internal items
#[doc(hidden)]
pub fn internal_detail() { ... }

Testing

Test Public API

// tests/integration.rs
use my_library::{Client, Config};

#[test]
fn client_connects_successfully() {
    let client = Client::new(Config::default());
    assert!(client.is_valid());
}

Doc Tests Run by Default

/// Creates a new instance.
///
/// # Examples
///
/// ```
/// let instance = my_library::Instance::new();
/// assert!(instance.is_valid());
/// ```
pub fn new() -> Self { ... }

Cargo.toml Best Practices

[package]
name = "my-library"
version = "0.1.0"
edition = "2024"
rust-version = "1.85"  # MSRV - Rust 2024 edition requires 1.85+
description = "A brief description"
documentation = "https://docs.rs/my-library"
repository = "https://github.com/org/my-library"
license = "MIT OR Apache-2.0"
keywords = ["keyword1", "keyword2"]
categories = ["category"]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]