Skip to content

feat!: redesign TypedFlake around an attribute macro - #5

Merged
pokedotdev merged 23 commits into
mainfrom
redesign
Oct 5, 2026
Merged

pokedotdev merged 23 commits into
mainfrom
redesign

Conversation

@pokedotdev

@pokedotdev pokedotdev commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Redesigns TypedFlake for 0.2.0. See CHANGELOG.md for the changes and MIGRATION.md for moving from 0.1.

Replace the declarative `typedflake::id!()` macro with `#[derive(TypedFlake)]`
on user-defined structs, enabling users to freely add their own derives and
attributes alongside TypedFlake.

New workspace structure:
- typedflake: public facade re-exporting core + derive macro
- typedflake-core: runtime logic (config, context, generator, global, state)
- typedflake-macros: proc-macro crate implementing #[derive(TypedFlake)]

BREAKING CHANGE: `typedflake::id!(Name)` replaced by
`#[derive(TypedFlake)] pub struct Name(u64)` and
`typedflake::id!(Name, CONFIG)` replaced by
`#[derive(TypedFlake)] #[typedflake(config = CONFIG)] pub struct Name(u64)`
…e Config API

Remove unverifiable TWITTER/DISCORD/INSTAGRAM presets from Epoch, BitLayout,
and Config. Rename Config::new_unchecked to Config::new since it's already
const-validated via panic. Add inline #[typedflake(layout, epoch)] attribute
parameters to the derive macro for one-off configuration without separate
const declarations.

BREAKING CHANGE: Config::new_unchecked renamed to Config::new. Removed
Config::TWITTER, Config::DISCORD, BitLayout::TWITTER, BitLayout::DISCORD,
Epoch::TWITTER, Epoch::DISCORD, Epoch::INSTAGRAM.
Replace verbose free functions (set_defaults, set_default_config,
set_default_instance) with a DefaultsBuilder accessed via defaults().
New API: typedflake::defaults().config(...).instance(w, p).init()?
Record the target interface, decisions, legacy ID compatibility recipe, and implementation phases for the attribute-macro redesign.
Replace `#[derive(TypedFlake)]` with an attribute macro on `i64`/`u64`
newtypes, as described in PROPOSAL.md.

- Formats are `Format { epoch, bits }` constants or inline options, with
  one node field instead of worker and process, validated at compile time.
- Nodes are a plain `u32` or a `TypedNode` struct with named fields.
- Generation returns errors instead of blocking; `generate_blocking` and
  the optional Tokio `generate_async` wait for sequence capacity.
- `typedflake::init` installs one schema-preserving default node.
- Raw, string, Serde, SQLx, and postgres-types inputs share one
  validation path that rejects negative values and reserved bits.
- Merge `typedflake-core` into `typedflake`.

The clock is read after each load of the generation state, so a newer
millisecond stored by another thread is not reported as a rollback.
- Rewrite the README around `#[typedflake]`, with examples compiled as
  doctests.
- Add MIGRATION.md, including declarations that keep reading 0.1 IDs.
- Record the changes in CHANGELOG.md and the implementation notes in
  PROPOSAL.md.
- Update CLAUDE.md and AGENTS.md for the two-crate layout.
- Run CI against PostgreSQL, each feature alone, and rustdoc.
Panic in the declaration's own const instead of inside a called function.
The compile error now points at the `#[typedflake]` attribute with only the
reason, and no longer quotes standard library sources, which made the
pinned diagnostics depend on `rust-src` being installed.

Move the two remaining source-dependent rejections to `compile_fail`
doctests.
`typedflake::init` can now be called once for each node type, so a process
that mixes plain and typed nodes keeps the static `generate()` for every
ID. Previously only one node type could have a default and the others
needed explicit generators.

An ID still only receives a node of its own type. A missing default is
`GenerateError::NotInitialized { node }`, which replaces
`NodeSchemaMismatch`.

Database tests also treat an empty `TYPEDFLAKE_TEST_POSTGRES_URL` as unset.
Reading the clock between the load and the compare-and-swap left a window
of about 30 ns in which other threads changed the state, so the swap
failed almost every time under contention. A rollback is now confirmed
with a second reading taken after the load before it is reported.
The `alphabet` option of `#[typedflake]` adds `encode()` and `decode()`
for a fixed-length text form. Alphabets hold 2 to 94 ASCII characters and
are validated at compile time; presets are BASE36, BASE58, BASE62, and
BASE64_URL. Decoding accepts only the exact encoding and ends in the same
validation as every other constructor.
`typedflake::SerdeEncoded` serializes an ID as its encoded text and reads
only that exact text, since a decimal string can also be valid text in the
alphabet for a different ID. It needs the `alphabet` option and cannot be
combined with `typedflake::Serde` on one type.
It only imported AGENTS.md, which is the single contributor guide.
@pokedotdev
pokedotdev marked this pull request as ready for review October 5, 2026 06:09
@pokedotdev
pokedotdev merged commit 72f3cdb into main Oct 5, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant