一键导入
rust-semver
Guidelines and checklists for maintaining semantic versioning in Rust projects, including breaking change identification and mitigation strategies.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Guidelines and checklists for maintaining semantic versioning in Rust projects, including breaking change identification and mitigation strategies.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | Rust SemVer |
| description | Guidelines and checklists for maintaining semantic versioning in Rust projects, including breaking change identification and mitigation strategies. |
This skill provides comprehensive guidance on managing Semantic Versioning (SemVer) in Rust. Use this when planning API changes, performing refactors, or preparing for new releases to ensure backward compatibility or correctly identify breaking changes.
Version Format: MAJOR.MINOR.PATCH
0.y.z releases: changes in y = major, changes in z = minor
Working with Public Items:
Type and Representation Changes:
repr(packed), repr(align), repr(C) for types with public fieldsrepr(packed(N)) or repr(align(N)) if it changes alignment/layoutrepr(<int>) from enumrepr(<int>) enumrepr(transparent)repr(C) typesEnums:
#[non_exhaustive])Traits:
Generics:
Functions:
Attributes:
no_std support to requiring std#[non_exhaustive] to existing enum/variant/struct with no private fieldsCargo:
Adding Items:
Representation Changes:
repr(C) typesrepr(C) enum with #[non_exhaustive]repr(C) to default representationrepr(<int>) to enumrepr(transparent) to default representationGenerics:
Functions:
unsafe function safeCargo:
#![deny(warnings)])#[deprecated]pub use for re-export#[non_exhaustive] from the startDefault traitdefaultdep: syntax for optional dependenciesAPI Changes:
Type Layout:
repr attributes? → check table aboveDependencies:
Documentation:
no_std to std → MAJORstd = []package.rust-version in Cargo.toml#![deny(warnings)]| Change | Version | Note |
|---|---|---|
| Adding function | MINOR | Safe |
| Removing function | MAJOR | Use deprecation |
| Changing function parameters | MAJOR | Create new function |
| Adding trait method with default | MINOR | But may conflict |
| Changing trait method | MAJOR | Create new trait |
| Adding field to struct (all fields public) | MAJOR | Use #[non_exhaustive] |
| Adding field (has private fields) | MINOR | Safe |
Adding enum variant without non_exhaustive | MAJOR | Use #[non_exhaustive] |
Adding #[must_use] | MINOR | Lint, not breaking |
| Changing MSRV | MINOR* | *Per recommendations |
Adding repr(C) | MINOR | To default repr |
Removing repr(C) | MAJOR | If layout matters |
#[non_exhaustive]: Provides future flexibilitydyn Trait// MAJOR: Adding repr(packed) to any struct
#[repr(packed)]
pub struct Foo { pub a: u8, pub b: u32 }
// MINOR: Adding repr(C) to default repr
#[repr(C)]
pub struct Bar { pub x: i32 }
// MAJOR: Removing repr(transparent)
// was: #[repr(transparent)]
pub struct Wrapper<T>(T);
// MAJOR: Capturing more lifetimes in RPIT
// Before: impl Iterator + use<'a>
// After: impl Iterator + use<'a, 'b>
// MINOR: Capturing fewer lifetimes
// Before: impl Iterator + use<'a, 'b>
// After: impl Iterator + use<'a>
// Use this to prevent breaking changes from trait modifications
mod private {
pub trait Sealed {}
}
pub trait MyTrait: private::Sealed {
// Can safely add methods with defaults
fn new_method(&self) {}
}
impl private::Sealed for MyType {}
impl MyTrait for MyType {}
// Adding field to all-public struct
pub struct Config {
pub timeout: u64,
pub retries: u32,
// Adding `pub max_size: usize` breaks construction
}
// Changing function signature
pub fn process(data: Vec<u8>) { }
// to: pub fn process(data: &[u8]) { } // BREAKS!
// Adding non-defaulted trait item
pub trait Handler {
fn handle(&self);
// Adding `fn validate(&self) -> bool;` BREAKS!
}
// Use non_exhaustive from the start
#[non_exhaustive]
pub struct Config {
pub timeout: u64,
pub retries: u32,
}
impl Config {
pub fn new(timeout: u64, retries: u32) -> Self {
Self { timeout, retries }
}
}
// Create new function for signature changes
pub fn process_vec(data: Vec<u8>) { }
pub fn process(data: &[u8]) { } // New function, safe!
// Always provide defaults for trait items
pub trait Handler {
fn handle(&self);
fn validate(&self) -> bool { true } // Default provided
}
+ use<> to capture fewer → breaking changecargo-semver-checks on public API# Example CI check
- name: Check SemVer
run: |
cargo install cargo-semver-checks
cargo semver-checks check-release
Sometimes breaking changes are inevitable. When they are:
## Breaking Changes in v2.0.0
### Removed: `old_function`
- **Reason:** Superseded by more efficient implementation
- **Migration:** Use `new_function` instead
- **Example:**
```rust
// Before
old_function(data);
// After
new_function(&data);
```
Is it a public API change?
├─ No → Consider PATCH or MINOR (docs, internal changes)
└─ Yes → Continue
│
Does it remove/rename/change existing public items?
├─ Yes → MAJOR
└─ No → Continue
│
Does it add new requirements (trait items, bounds)?
├─ Yes → Check if defaulted
│ ├─ Not defaulted → MAJOR
│ └─ Defaulted → MINOR (possibly-breaking if conflicts)
└─ No → Continue
│
Does it change type layout/size/alignment?
├─ Yes → Check if well-defined
│ ├─ Well-defined → MAJOR
│ └─ Not well-defined → MINOR
└─ No → Likely MINOR
│
Document the change!