Repository navigation
Feat/infallible and sealed - #4
Merged
Merged
Conversation
Three changes, and a rename that should have happened at 0.1. MapFrom/map_into were the fallible pair, which left every call site writing `?` for a conversion that cannot fail and forced enclosing functions to return Result for no reason. They are now TryMapFrom/try_map_into, mirroring From/TryFrom, and the plain names belong to a new infallible pair. `magic_map!(infallible ...)` emits it. The claim is checked structurally rather than trusted: the expansion contains no `?`, so a field pair that only has a TryMapFrom route fails to resolve. String -> Uuid parses, so claiming infallible over it does not compile. Infallible mappings also get the fallible half for free, written out rather than blanket-impl'd because `impl<S, D: MapFrom<S>> TryMapFrom<S> for D` overlaps every generated impl and coherence rejects it. Sources may now be `&T`. The tuple form already took references in element position; only the top-level parse refused, which left a borrowed source spelled as a one-tuple. `#[mapped]` is the attribute form of the derive, and `#[mapped(sealed)]` adds #[non_exhaustive] plus a hidden all-fields constructor. From another crate the type then has no struct expression, so a hand-rolled field-by-field copy stops compiling — and so does `impl From<A> for T`, because that impl body cannot construct its own output either. Forbidding the manual map forbids the manual From with it; they are one mechanism, not two. It has to be an attribute because a derive is additive-only and can never place an attribute on the item it is deriving. The constructor is public: an expansion holds no privilege a hand-written line lacks, so this makes the wrong path ugly and greppable rather than impossible. Sealing is skipped where it would only cost — unit and tuple structs, enums, and field-less markers like a proto Empty.
README had the rename but none of the three features, and there was no upgrade path written down. MIGRATING.md covers the sed, what each capability buys, and — because it is the part people will get wrong — where sealing does and does not reach: the boundary is the crate, not the directory, so a helper struct declared next to its mapper is not protected and moving code between modules changes nothing.
The struct path already branched on infallible; the enum path hardcoded Ok(match ...), so an infallible enum-to-enum declaration failed with a type mismatch whose span landed on the derive. Variant-to-variant over unit enums cannot fail, so the bare match is the infallible body.
The infallible expansion funnelled every nested field through the global MapFrom, which a foreign→foreign pair can never implement, so an infallible fn-form mapping could not nest another one — in a layered codebase that is most mappings. magic_map_scope! now plants LocalMapFrom (infallible) beside the fallible funnel, which is renamed LocalTryMapFrom to mirror the 0.4 trait split. Infallible fn-forms register in both. Leaves gained fallibility: map_identity!/map_display! emit the MapFrom twin (identity and Display cannot fail), DateTime<Utc>→String rfc3339 is infallible, and magic_map_leaves!/scope leaves take an 'infallible' prefix on custom pairs — one MapFrom impl then backs both funnels.
Sealing cannot reach types local to the mapping crate, conversions out of a sealed type, or anything unsealed. The lint covers those three: a syn-based binary that walks source trees and flags every impl of From/Into/TryFrom/TryInto. Error conversions (either side named *Error) are exempt — that is how ? bubbles between layers — and the allowlist fails on stale entries, so it only shrinks. MIGRATING.md gains the leaf-marking step and the lint section.
The attribute form parsed export = ".." and threw it away, and left the #[magic_map(export)] helper dangling on the re-emitted item where no derive remains to claim it. Both forms now feed schema_for the same override, and prost trees can seal blanket-style while keeping their per-type export disambiguations.
…ports magic_map_scope! expanded ::uuid::Uuid and friends in the CALLING crate, so a crate mapping only strings still needed uuid, rust_decimal, chrono and serde_json as direct dependencies. The feature-gated groups now name those types through $crate::__rx, which resolves against this crate's own dependency set.
Version strings catch up to 0.4; the infallible section explains enum mappings and fn-form composition through the local funnel; leaves gain the fallibility model (map_identity!/map_display! emit the MapFrom twin, 'infallible' custom pairs back both funnels with one impl); the prost recipe seals model packages path-scoped; and magic-map-lint gets its own section — install, exemptions, shrink-only allowlist, and the division of labour with sealing. MIGRATING adds the dependency dividend, the parameter-construction bucket, and the sealed-pattern gotcha.
__magic_map_leaf_impl! was invoked nowhere and its emitted impl no longer matched the renamed local trait — gone. mapped() re-implemented the #[magic_map(export)] parser schema_for already owns; schema_for now runs before the helper attr is stripped, so one loop reads it and a helper beats the attribute argument. magic_map_lint drops an unused quote dependency and syn's printing feature, and an unreadable --allow path is a usage error (exit 2), not a panic.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.