pin-project-lite
A lightweight Rust macro crate for safe pin projection, implemented with declarative macros instead of proc-macros.
Repository Health
Technical Analysis
pin-project-lite provides the pin_project! macro, which generates a safe projection type for a struct or enum so that individual fields can be accessed as Pin<&mut T> or plain &mut T references depending on whether they’re marked #[pin]. It solves the same core problem as the pin-project crate — writing self-referential or !Unpin futures and other pinned data structures without unsafe code — but is implemented entirely with macro_rules! declarative macros rather than a proc-macro crate.
That implementation choice is the crate’s entire reason to exist: for crates that don’t already depend on syn/quote/proc-macro machinery elsewhere in their dependency graph, pin-project-lite avoids adding that (relatively heavy) compile-time dependency chain. The tradeoff is a narrower feature set than full pin-project — no custom Unpin opt-outs via UnsafeUnpin, no tuple struct/variant support, and much less helpful compiler error messages on misuse.
What You Get
- The
pin_project!macro, applied to a struct or enum definition, generating a.project()method returning a projection type - Per-field
#[pin]attribute to mark which fields should project toPin<&mut T>versus a plain&mut T - Enum support via a named projection type (e.g.
#[project = EnumProj]) - The same safety guarantees as full
pin-project— no unsafe code required in downstream crates - Zero proc-macro dependency chain, keeping compile times and dependency trees lean for crates that don’t already pull in
syn/quote
Common Use Cases
- Implementing custom
Future/Streamtypes by hand that hold both pinned (self-referential) and unpinned fields - Any low-level async runtime or combinator crate wanting pin projection without adding a proc-macro dependency chain
- Libraries with strict compile-time or dependency-tree budgets that still need safe pinned-field access
- Learning or prototyping pin projection where full pin-project’s more helpful error messages aren’t yet needed
Under The Hood
Architecture: The entire implementation lives in a single src/lib.rs (1,772 lines), built around the pin_project! declarative macro. Rather than parsing arbitrary Rust syntax with a proc-macro parser, it uses macro_rules!’s token-tree matching to recognize struct/enum definitions, per-field #[pin] attributes, and optional projection-type naming, then emits a projection struct/enum plus a .project() method and the necessary (encapsulated, checked) unsafe pinning logic. Because macro_rules! matching is far less flexible than a full parser, the macro supports a deliberately constrained input grammar — no tuple structs/variants, no custom Unpin opt-out — which keeps the matching rules tractable.
Tech Stack: Pure Rust, edition 2018, MSRV 1.37, zero dependencies of any kind at the crate level (dev-dependencies only, for its own test suite: macrotest, rustversion, static_assertions, trybuild). A [workspace.lints] block shared across the author’s (taiki-e) crates enables clippy::pedantic plus several rustc lints, and the workspace includes tests/no-core, tests/no-std, and tests/lint sub-crates for isolated environment testing.
Code Quality: The crate uses trybuild and macrotest for compile-fail and macro-expansion snapshot testing respectively, which is the standard rigorous testing approach for macro crates where correctness means “generates exactly the expected code” as much as “compiles.” undocumented_unsafe_blocks is enabled as a workspace lint, forcing every unsafe block the macro generates to carry a safety-justification comment — meaningful given that the entire crate’s value proposition is guaranteeing safety around raw pinning. A DEVELOPMENT.md documents the contribution/testing workflow.
API Design: The macro’s surface is intentionally minimal — wrap a struct/enum in pin_project! { ... }, mark fields #[pin], call .project() — mirroring pin-project’s API closely enough that the README documents it as a drop-in-compatible subset. The crate is explicit in its own docs about what it doesn’t support (tuple structs, UnsafeUnpin, helpful macro error messages), directing users to the full pin-project crate the moment their needs exceed this one, which is an unusually honest API-scoping decision for a widely-depended-on crate.
Used by 3 apps in this directory
headroom
AI Development · Developer Tools
Compress everything your AI agent reads — tool outputs, logs, RAG chunks, and files — before it reaches the LLM, achieving 60–95% fewer tokens with the same answers.
hoop
Security · Monitoring
A wire-protocol gateway that enforces data masking, command blocking, approval workflows, and full session recording for engineers and AI agents accessing production infrastructure.
Meilisearch
Search
Lightning-fast hybrid search engine with AI-powered semantic and full-text retrieval for modern applications.