home / skills / huiali / rust-skills / rust-linear-type

rust-linear-type skill

/skills/rust-linear-type

This skill analyzes and applies linear type principles to Rust ownership, ensuring resource safety, unique ownership, and deterministic destruction.

npx playbooks add skill huiali/rust-skills --skill rust-linear-type

Review the files below or copy the command above to add this skill to your agents.

Files (4)
SKILL.md
5.1 KB
---
name: rust-linear-type
description: 线性类型与资源管理专家。处理 Destructible, 资源清理, RAII, unique object, linear semantics, 线性语义, 资源所有权, 独占语义--- # 线性类型 ## 核心问题 **如何保证资源不被泄漏或被重复释放?** 线性类型语义保证每个资源被精确使用一次。
---


## 线性类型 vs Rust 所有权

| 特性 | Rust 所有权 | 线性类型 |
|-----|------------|---------|
| 移动语义 | ✓ | ✓ |
| 复制语义 | 可选 | ✗ |
| 析构保证 | Drop | Destructible |
| 借用 | ✓ | ✗ 或受限 |
| 多重所有 | Rc/Arc | ✗ |

Rust 默认不是线性类型,但可以通过模式实现线性语义。


## Destructible Trait

```rust
// 线性类型的核心:Destructible 保证析构
use std::mem::ManuallyDrop;

struct LinearBuffer {
    ptr: *mut u8,
    size: usize,
}

impl Drop for LinearBuffer {
    fn drop(&mut self) {
        unsafe {
            std::alloc::dealloc(self.ptr, Layout::array::<u8>(self.size).unwrap());
        }
    }
}

// 防止双重释放
struct SafeLinearBuffer {
    inner: ManuallyDrop<LinearBuffer>,
}

impl Drop for SafeLinearBuffer {
    fn drop(&mut self) {
        // 确保只释放一次
        unsafe {
            ManuallyDrop::drop(&mut self.inner);
        }
    }
}
```


## 独占对象模式

```rust
// 确保对象只能被移动,不能被复制
#[derive(Copy, Clone)]
struct FileHandle(u32);

impl FileHandle {
    // 私有构造函数,防止外部直接创建
    fn from_raw(fd: u32) -> Self {
        Self(fd)
    }
}

// 包装为线性类型
struct LinearFile {
    fd: FileHandle,
}

impl LinearFile {
    pub fn open(path: &str) -> Result<Self, std::io::Error> {
        // 打开文件,返回线性文件句柄
        Ok(LinearFile {
            fd: FileHandle::from_raw(0), // 示例
        })
    }

    // consume() 方法消费 self,保证线性使用
    pub fn consume(self) -> FileHandle {
        self.fd
    }
}
```


## 资源令牌模式

```rust
// 线性资源令牌
struct ResourceToken<T> {
    resource: T,
    consumed: bool,
}

impl<T> ResourceToken<T> {
    pub fn new(resource: T) -> Self {
        Self {
            resource,
            consumed: false,
        }
    }

    // 消费令牌,返回资源
    pub fn consume(mut self) -> T {
        self.consumed = true;
        self.resource
    }

    // 检查是否已消费
    pub fn is_consumed(&self) -> bool {
        self.consumed
    }
}

// 使用示例
fn process_resource(token: ResourceToken<Vec<u8>>) -> Vec<u8> {
    // 在这里处理资源
    let data = token.consume(); // 消费后令牌失效
    data
}
```


## 交易式资源管理

```rust
// 两阶段提交模式
struct Transaction<T> {
    data: T,
    committed: bool,
}

impl<T> Transaction<T> {
    pub fn new(data: T) -> Self {
        Self {
            data,
            committed: false,
        }
    }

    pub fn commit(mut self) -> T {
        self.committed = true;
        self.data
    }

    // 回滚:丢弃资源
    pub fn rollback(self) {
        // 自动调用 Drop
    }
}

// 使用
fn example() -> Result<i32, ()> {
    let tx = Transaction::new(100);
    
    if condition {
        tx.commit(); // 提交,返回数据
    } else {
        tx.rollback(); // 回滚,丢弃
    }
}
```


## Unique 指针模式

```rust
// 类似 C++ unique_ptr 的线性指针
struct UniquePtr<T: Sized> {
    ptr: *mut T,
    _marker: std::marker::PhantomData<T>,
}

impl<T> UniquePtr<T> {
    pub fn new(data: T) -> Self {
        let ptr = Box::into_raw(Box::new(data));
        Self {
            ptr,
            _marker: std::marker::PhantomData,
        }
    }

    pub fn as_ref(&self) -> Option<&T> {
        if self.ptr.is_null() {
            None
        } else {
            Some(unsafe { &*self.ptr })
        }
    }

    // 消费自身,返回 Box
    pub fn into_box(self) -> Box<T> {
        unsafe {
            let ptr = self.ptr;
            std::mem::forget(self);
            Box::from_raw(ptr)
        }
    }
}

impl<T> Drop for UniquePtr<T> {
    fn drop(&mut self) {
        if !self.ptr.is_null() {
            unsafe {
                Box::from_raw(self.ptr);
            }
        }
    }
}
```


## Rust 中的线性语义场景

| 场景 | 线性保证 | 模式 |
|-----|---------|------|
| 文件句柄 | close 恰好一次 | RAII + Drop |
| 网络连接 | close 恰好一次 | RAII + Drop |
| 内存分配 | free 恰好一次 | RAII + Drop |
| 锁 | unlock 恰好一次 | RAII + Drop |
| 事务 | commit 或 rollback | 交易式资源管理 |
| FFI 资源 | release 恰好一次 | 资源令牌 |


## 避免的模式

| 反模式 | 问题 | 正确做法 |
|-------|------|---------|
| Clone 允许复制 | 破坏线性语义 | 使用 move 语义 |
| Rc/Arc 共享 | 多重所有 | 线性令牌 |
| 手动管理生命周期 | 容易出错 | RAII + Drop |
| 跳过 Drop | 资源泄漏 | 使用 scope API |


## 与其他技能关联

```
rust-linear-type
    │
    ├─► rust-resource → RAII 和 Drop 实现
    ├─► rust-ownership → 所有权模式
    └─► rust-unsafe → 底层资源操作
```

Overview

This skill is a Rust linear-type and resource-management expert focused on designing and verifying linear semantics, destructible resources, and exclusive ownership patterns. It provides concrete patterns (Destructible, unique pointers, resource tokens, transactional resources) and guidance to ensure resources are released exactly once. The goal is practical recommendations and code-level strategies to implement linear behavior on top of Rust’s ownership model.

How this skill works

The skill inspects code and design to detect non-linear patterns (unwanted Clone/Rc, manual frees, missing Drop guarantees) and recommends linear alternatives: private constructors, consume-by-value APIs, ManuallyDrop guards, UniquePtr semantics, and transaction-style commit/rollback. It evaluates resource lifecycle points (creation, transfer, consumption, Drop) and suggests refactors to enforce single-consume semantics. It also proposes test cases and safety checks for FFI and unsafe code paths.

When to use it

  • Implementing RAII for OS handles, sockets, or allocated memory that must be freed exactly once.
  • Designing FFI wrappers where external resources require precise release semantics.
  • Building APIs that must prevent duplication or shared ownership (e.g., exclusive file handles).
  • Creating transactional resource flows that commit or rollback deterministically.
  • Hardening unsafe code paths to avoid double-free, use-after-free, or leaked resources.

Best practices

  • Prefer move/consume APIs: take self by value and return resources via consume() to guarantee single use.
  • Avoid deriving Clone/Copy for resource-owning types; use private constructors to control creation.
  • Wrap raw allocations in Drop or Destructible implementations and use ManuallyDrop to prevent double-free when needed.
  • Model temporary ownership with ResourceToken or Transaction types to express consumed vs. unconsumed states.
  • Prefer RAII + Drop for common resources and reserve unsafe patterns for minimal, reviewed hotspots.
  • Provide tests for lifecycle: ensure close/free called exactly once and that rollback paths drop safely.

Example use cases

  • Wrap a platform file descriptor in a LinearFile type that can be moved and consumed but never cloned.
  • Implement a UniquePtr for a C-allocated buffer returned by FFI and ensure it is freed exactly once in Drop.
  • Create a Transaction wrapper around in-memory state or external resources to support commit/rollback semantics.
  • Use ResourceToken to model a one-time consumable API for streaming or single-use cryptographic keys.
  • Audit a codebase for Rc/Arc misuse on handles and replace with linear tokens or exclusive types where appropriate.

FAQ

Can Rust’s ownership already give linear guarantees?

Rust’s ownership and move semantics provide much of the ground work, but Rust is not strictly linear: Clone/Copy and shared pointers permit non-linear use. This skill shows patterns to enforce one-time consumption and prevent accidental duplication.

When should I use ManuallyDrop?

Use ManuallyDrop when you need explicit control over destructor timing (e.g., to avoid double-free during a controlled move or when composing destructors), and ensure unsafe blocks are minimal and reviewed.