feat: expose tags() and tags_mut() on all profile types#26
Conversation
Add public tag map accessors to RawProfile, all device-class wrappers (DisplayProfile, InputProfile, etc.), and the Profile enum, so callers no longer need to work with RawProfile directly just to read or modify tags. - tags() returns &IndexMap<TagSignature, ProfileTagRecord> - tags_mut() returns &mut IndexMap<TagSignature, ProfileTagRecord>, enabling removal and direct insertion of tags — operations not possible through the existing builder API - Update lib.rs Quick Start docs with examples for reading header fields, reading tag values, and removing a tag via tags_mut() - README regenerated from updated doc comments Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR exposes tag-map accessors (tags() / tags_mut()) across all profile entry points (raw profile, each device-class wrapper, and the Profile enum) so callers can read and directly edit ICC tags without needing to unwrap to RawProfile. It also expands the crate’s Quick Start documentation (and regenerates README.md) to show common header/tag inspection and mutation workflows.
Changes:
- Add
tags()andtags_mut()toRawProfile,Profile, and all device-class wrapper types via delegation. - Update crate-level docs in
src/lib.rswith new “Read header fields”, “Read tag values”, and atags_mut()example. - Regenerate
README.mdfrom the updated doc comments.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/profile/raw_profile.rs | Adds tags() / tags_mut() accessors on RawProfile. |
| src/profile/delegate.rs | Delegates tags() / tags_mut() to all device-class wrappers. |
| src/profile.rs | Adds tags() / tags_mut() on the Profile enum forwarding to RawProfile. |
| src/lib.rs | Expands Quick Start docs to demonstrate reading headers/tags and mutating tags. |
| README.md | Regenerated output reflecting the updated crate-level docs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// Tags are stored in insertion order, which matches the order they appear in the | ||
| /// original profile's tag table. |
There was a problem hiding this comment.
Same as RawProfile::tags() docs: stating the order "matches the order they appear in the original profile's tag table" can become false after callers mutate the map via tags_mut(). Consider qualifying this statement (e.g. "for profiles read from disk, before mutation").
| /// Tags are stored in insertion order, which matches the order they appear in the | |
| /// original profile's tag table. | |
| /// Tags are stored in insertion order. For profiles read from disk, this initially | |
| /// matches the order they appear in the original profile's tag table, before any | |
| /// mutation via [`Self::tags_mut`]. |
|
|
||
| /// Returns a reference to the profile's tag map, keyed by [`TagSignature`]. | ||
| /// | ||
| /// Each [`ProfileTagRecord`] holds the tag's offset, size, and parsed [`Tag`] data. |
There was a problem hiding this comment.
Doc comment says ProfileTagRecord holds "parsed" Tag data, but Tag/TagData here is still the typed wrapper around the raw bytes (the fully parsed/serializable representation is ParsedTag via Tag::to_parsed()). Consider rewording to avoid implying the tag payload has already been parsed (e.g. say "typed Tag data" or reference ParsedTag explicitly).
| /// Each [`ProfileTagRecord`] holds the tag's offset, size, and parsed [`Tag`] data. | |
| /// Each [`ProfileTagRecord`] holds the tag's offset, size, and typed [`Tag`] data. |
| /// Tags are stored in insertion order, which matches the order they appear in the | ||
| /// original profile's tag table. | ||
| pub fn tags(&self) -> &IndexMap<TagSignature, ProfileTagRecord> { | ||
| &self.tags | ||
| } | ||
|
|
||
| /// Returns a mutable reference to the profile's tag map, keyed by [`TagSignature`]. | ||
| /// | ||
| /// Allows inserting, replacing, or removing tags directly. Note that removing |
There was a problem hiding this comment.
The docs state the IndexMap insertion order "matches the order they appear in the original profile's tag table"; that’s only guaranteed immediately after reading. Since tags_mut() allows removal/reinsertion, the order can diverge from the original. Consider qualifying the statement (e.g. "when read from disk" / "until modified").
| /// Tags are stored in insertion order, which matches the order they appear in the | |
| /// original profile's tag table. | |
| pub fn tags(&self) -> &IndexMap<TagSignature, ProfileTagRecord> { | |
| &self.tags | |
| } | |
| /// Returns a mutable reference to the profile's tag map, keyed by [`TagSignature`]. | |
| /// | |
| /// Allows inserting, replacing, or removing tags directly. Note that removing | |
| /// Tags are stored in insertion order. Immediately after reading a profile from | |
| /// disk, that order matches the order the tags appear in the original profile's | |
| /// tag table. After modifications via [`Self::tags_mut`], the order may differ. | |
| pub fn tags(&self) -> &IndexMap<TagSignature, ProfileTagRecord> { | |
| &self.tags | |
| } | |
| /// Returns a mutable reference to the profile's tag map, keyed by [`TagSignature`]. | |
| /// | |
| /// Allows inserting, replacing, or removing tags directly. Removing and | |
| /// reinserting tags may change their iteration order. Note that removing |
| /// Each [`ProfileTagRecord`] holds the tag's offset, size, and parsed [`crate::tag::Tag`] data. | ||
| /// Tags are stored in insertion order, which matches the order they appear in the | ||
| /// original profile's tag table. |
There was a problem hiding this comment.
Doc comment says ProfileTagRecord holds "parsed" Tag data, but the fully parsed representation is crate::tag::ParsedTag (via Tag::to_parsed()). Consider rewording to avoid confusion about whether Tag is already parsed vs still a typed wrapper around the raw bytes.
| /// Each [`ProfileTagRecord`] holds the tag's offset, size, and parsed [`crate::tag::Tag`] data. | |
| /// Tags are stored in insertion order, which matches the order they appear in the | |
| /// original profile's tag table. | |
| /// Each [`ProfileTagRecord`] holds the tag's offset, size, and [`crate::tag::Tag`] value. | |
| /// Use [`crate::tag::Tag::to_parsed()`] to obtain the fully parsed | |
| /// [`crate::tag::ParsedTag`] representation when needed. Tags are stored in | |
| /// insertion order, which matches the order they appear in the original profile's | |
| /// tag table. |
- Replace "parsed Tag data" with "typed Tag value" — Tag/TagData is a typed bytes wrapper; ParsedTag (via to_parsed()) is the fully parsed form. Add a reference to Tag::to_parsed() and ParsedTag. - Qualify the insertion-order guarantee: it holds immediately after reading from disk, but may change after mutation via tags_mut(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
tags()returning&IndexMap<TagSignature, ProfileTagRecord>toRawProfile, all eight device-class wrappers, and theProfileenum — callers no longer need to useRawProfiledirectly just to read tagstags_mut()returning&mut IndexMap<TagSignature, ProfileTagRecord>with the same coverage, enabling removal and direct insertion of tags — operations not currently possible through the builder APIlib.rswith three new subsections: Read header fields, Read tag values, and atags_mut()example under Modify an existing profileTest plan
cargo test— all 44 tests passcargo xtask doc— docs build clean, README up to date🤖 Generated with Claude Code