https://github.com/kyza/internal
Internal fields in Rust.
https://github.com/kyza/internal
features internal macro private proc-macro proc-macro-attributes rust
Last synced: 11 months ago
JSON representation
Internal fields in Rust.
- Host: GitHub
- URL: https://github.com/kyza/internal
- Owner: Kyza
- License: mit
- Created: 2023-10-24T16:41:44.000Z (over 2 years ago)
- Default Branch: trunk
- Last Pushed: 2024-01-13T04:30:16.000Z (about 2 years ago)
- Last Synced: 2025-02-28T03:52:03.520Z (12 months ago)
- Topics: features, internal, macro, private, proc-macro, proc-macro-attributes, rust
- Language: Rust
- Homepage:
- Size: 16.6 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# internal
Private fields were a mistake.
## What?
Ok, maybe that's a bit of an exaggeration.
Private fields aren't bad; they have a purpose:
1. To allow library developers to make breaking changes to things without
making major [semver](https://semver.org/) jumps.
2. To prevent consumers from accidentally causing UB.
3. To enable compiler optimizations.
But there's a better way.
The main problem with private fields is, well, it makes things private.
It's too easy to lock potentially useful functionality away from your users.
A solution to that problem is internal fields, but Rust doesn't have that
feature. This crate brings it to Rust via a proc macro and a feature flag.
### How do internal fields work?
By default, internal fields can't be accessed, but they can be enabled and
used when absolutely necessary.
It's a balanced solution to both ease of library development and freedom
of library usage. It's easy to tell what could change, but nobody's
limited or burdened. On top of all this, the compiler can still take
advantage of performance improvements when internal fields aren't accessed.
The `internal` crate does it "the Rust way" by exposing the fields only
when the `"internal"` feature for the library is enabled. It also adds a
doc comment warning to the top of all internal fields to make it clear
when something is internal.
## Usage
```bash
cargo add internal
```
To mark something as internal, use the `internal` proc macro. It
effectively replaces private fields because those are useless when
internal fields exist.
The macro works recursively to mark everything under it that's private as
internal instead. So if you define `#[internal] mod stuff {...}`, anything
inside and including `stuff` that's private will become internal. If you
were to make `stuff` public, it would always be public itself, but still
apply internal recursively.
### `your_lib`
```rs
use internal::internal;
#[internal]
fn internal_fn(arg: InternalStruct) {
// ...
}
#[internal]
#[derive(Clone)]
struct InternalStruct {
field: PrivateThing
}
#[internal]
mod internal_mod {
pub struct PublicStruct {
internal_field: PublicThing
}
}
```
### `consumer`
```toml
# Cargo.toml
your_lib = { features = ["internal"] }
```
```rs
// mod.rs
// If the `internal` feature is explicitly enabled,
// anything marked as internal will become public.
use your_lib::{internal_fn, InternalStruct, internal_mod};
internal_fn(InternalStruct {
field: ...
});
// Everything gets publicized recursively.
private_mod::PublicStruct {
internal_field: ...
}
```