Repository navigation
Add option to generate typed constants from DBC attributes - #175
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
are there any existing examples of this in https://github.com/cantools/cantools in their tests/files? |
|
@nyurik This PR allows users to extract any arbitrary
|
|
@nyurik I've added some additional test cases using the |
There was a problem hiding this comment.
Pull request overview
Adds a new codegen configuration option to emit typed associated constants on generated message types, where the values are sourced from DBC BA_ attributes (with optional fallback to BA_DEF_DEF_ defaults), derived signal layout fields, and/or literals. This enables exposing per-message/per-signal metadata (e.g., AUTOSAR E2E / SecOC parameters) in a structured way in the generated Rust API.
Changes:
- Introduce
Config::attribute_structsplus supporting public spec types (AttributeStruct,AttributeScope,AttributeField,FieldSource) and generation logic insrc/lib.rs. - Add an end-to-end example and README documentation demonstrating how users map struct fields to DBC attributes/layout/literals.
- Add extensive tests covering success cases (scopes, defaults, layouts) and error cases (invalid sources, collisions, missing values).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| tests/attribute_structs.rs | New tests validating attribute-driven constant generation and error handling. |
| src/lib.rs | Implements attribute-struct specs, validation, attribute lookup/defaulting, and code emission into message impl blocks. |
| README.md | Documents the new attribute_structs feature and provides usage/example output. |
| examples/attribute_structs.rs | Adds a runnable example showing signal/message-scoped attribute structs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@felixvanoost I ran some more AI on this, with some additional thoughts of mine. I asked AI also to consider if any of this functionality should be moved up to can-dbc crate, and it did find a few ones. VerdictThe direction is sound and worth merging, with a few things to fix first. The feature is genuinely useful, opt-in (zero effect when unused), avoids hard-coding OEM attribute names into the generator, and the tests are thorough. But there are two API-evolvability problems, one real compile-breaking edge case, and three helper functions that belong in can-dbc. Why it's neededAutomotive DBCs (especially AUTOSAR-flavored ones) carry per-message/per-signal metadata in Could a user do this themselves with can-dbc in their own build.rs? Mostly yes — What should move to can-dbcThe three lookup helpers added at lib.rs:1544-1570 are pure DBC queries with zero codegen logic:
can-dbc already has exactly this pattern of methods on
I'd add these as A real bug: ENUM attributes can generate non-compiling codeVerified against the cantools fixture the PR itself uses: Internal duplication and smells
API-evolvability concerns worth settling before merge
Suggested pathBefore merging the code: (1) land |
|
@nyurik I've opened a PR to move the helper functions into |
Adds methods to lookup DBC attributes: `message_attribute`, `signal_attribute`, `attribute_default`, `resolved_message_attribute` and `resolved_signal_attribute`. These will be used in oxibus/dbc-codegen#175 and oxibus/dbc-codegen#176. --------- Co-authored-by: Yuri Astrakhan <YuriAstrakhan@gmail.com>
|
@nyurik I've updated |
b1c54a6 to
1d5a89b
Compare
for more information, see https://pre-commit.ci
1ec82f4 to
85bdd70
Compare
nyurik
left a comment
There was a problem hiding this comment.
overall seems good to go. One minor question about example - not a blocker though
nyurik
left a comment
There was a problem hiding this comment.
P.S. I disabled auto-merge to let you figure out what you want to do with the example, and once done, feel free to merge.
3ee3e5f to
4e22131
Compare
Generates the following new constants per message: - `MESSAGE_SIZE` in bytes. This avoids the overhead of using `raw().len()` or `embedded_can::Frame::dlc()` and makes the size known at compile-time. - `MESSAGE_CYCLE_TIME` containing the value from the corresponding `GenMsgCycleTime` DBC attribute when it is present. This PR should be stacked on top of #175.
## 🤖 New release
* `dbc-codegen`: 0.3.0 -> 0.4.0 (⚠ API breaking changes)
* `dbc-codegen-cli`: 0.3.0 -> 0.4.0
### ⚠ `dbc-codegen` breaking changes
```text
--- failure function_missing: pub fn removed or renamed ---
Description:
A publicly-visible function cannot be imported by its prior path. A `pub use` may have been removed, or the function itself may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.50.0/src/lints/function_missing.ron
Failed in:
function dbc_codegen::codegen, previously in file /tmp/.tmp0XWOqx/dbc-codegen/src/lib.rs:24
```
<details><summary><i><b>Changelog</b></i></summary><p>
## `dbc-codegen`
<blockquote>
##
[0.4.0](v0.3.0...v0.4.0) -
2026-09-22
### Added
- *(fuzz)* make fuzz compile/run
([#140](#140))
- optional padding bit value
([#184](#184))
- add `DBC_FILE_NAME` + ver, proper code formatting
([#131](#131))
- [**breaking**] streamline DBC code generation and file writing
([#128](#128))
### Fixed
- support large min/max values without precision loss
([#152](#152))
- handle duplicate signal names
([#126](#126))
- handle empty relevant msgs in from_can_message
([#125](#125))
- fix typo
- fix formatting errors
- fix factor/offset not getting applied to 0 for unsigned case
- fix duplicate enum names on multiplex messages
- fix issue where signed signals would be rendered as unsigned
### Other
- 2024 edition, bump deps, minor fixes
([#196](#196))
- [pre-commit.ci] pre-commit autoupdate
([#189](#189))
- *(deps)* bump actions/checkout from 6 to 7 in the
all-actions-version-updates group across 1 directory
([#191](#191))
- Remove unsafe from generated MESSAGE_ID constants
([#194](#194))
- Generate raw signal getters and setters
([#193](#193))
- Support relation attributes in attribute_structs
([#192](#192))
- Generate enum-typed setters and constructors for signals with value
descriptions ([#178](#178))
- Emit MESSAGE_CYCLE_TIME as integer
([#186](#186))
- Generate message size and cycle time consts
([#176](#176))
- Add option to generate typed constants from DBC attributes
([#175](#175))
- update can-dbc
([#181](#181))
- rust ver bump ([#182](#182))
- cleanup clippy, justfile, and proj cleanup
([#180](#180))
- *(deps)* bump the all-cargo-version-updates group across 1 directory
with 4 updates ([#172](#172))
- *(deps)* bump codecov/codecov-action from 6 to 7 in the
all-actions-version-updates group
([#165](#165))
- *(deps)* bump the all-cargo-version-updates group across 1 directory
with 4 updates ([#168](#168))
- *(deps)* bump the all-cargo-version-updates group across 1 directory
with 3 updates ([#163](#163))
- *(deps)* bump the all-cargo-version-updates group with 2 updates
([#161](#161))
- *(deps)* bump the all-cargo-version-updates group across 1 directory
with 2 updates ([#158](#158))
- *(deps)* bump the all-actions-version-updates group across 1 directory
with 2 updates ([#159](#159))
- update expected errors to Rust 1.94
([#153](#153))
- *(deps)* bump the all-cargo-version-updates group across 1 directory
with 2 updates ([#145](#145))
- *(deps)* bump insta from 1.46.2 to 1.46.3 in the
all-cargo-version-updates group
([#143](#143))
- upgrade to rust 1.93 stderr
([#142](#142))
- *(deps)* bump the all-cargo-version-updates group across 1 directory
with 4 updates ([#141](#141))
- [**breaking**] remove main fn from generated code
([#138](#138))
- make many rendering fn methods on config
([#133](#133))
- *(deps)* bump clap from 4.5.54 to 4.5.55 in the
all-cargo-version-updates group
([#134](#134))
- use `quote` crate to handle str escaping
([#132](#132))
- noop - dedup, cleanup, new type abstraction
([#130](#130))
- update shared tests, bump deps, freeze to rust 1.92
([#127](#127))
- *(deps)* bump can-dbc from 8.0.0 to 8.0.1 in the
all-cargo-version-updates group
([#129](#129))
- do not clean lock
- bump dependencies and enable verbose output for release actions
([#120](#120))
- [pre-commit.ci] pre-commit autoupdate
([#119](#119))
- Bump the all-cargo-version-updates group across 1 directory with 2
updates ([#118](#118))
- refactor write functions, improve CI, MSRV
([#116](#116))
- minor code cleanup
([#114](#114))
- generate and compile all .dbc files from test repo
([#113](#113))
- allow generated file to be used with `include!`
([#108](#108))
- Bump the all-cargo-version-updates group across 1 directory with 2
updates ([#111](#111))
- minor justfile fix, editorconfig
([#112](#112))
- Bump actions/cache from 4 to 5 in the all-actions-version-updates
group ([#110](#110))
- OxiBUS onboarding cleanup
([#102](#102))
- run `just fmt` to cleanup imports
([#107](#107))
- Bump the all-cargo-version-updates group across 1 directory with 9
updates ([#106](#106))
- upgrade to can-dbc v8
([#101](#101))
- Bump actions/checkout from 1 to 6 in the all-actions-version-updates
group ([#104](#104))
- *(CI)* minor CI updates, automate dependabot
([#103](#103))
- Add optional defmt::Format support for generated types
- Merge pull request #85 from inomotech-foss/fix-mux-msg-id
- Use message name instead of self
- Generate embedded_can::Frame trait for each frame
- Represent CAN message IDs as embedded_can::Id to support extended IDs
- Fix issue with decoding signed values of non-standard length
- revert change to Cargo.toml, not necessary
- address clippy's concerns (thanks clippy), enhance comments
- make can-messages dependency optional so it doesn't pull in std
- reduce diff against main
- handle more edge cases, use i128 as the maximum type
- reorder lines to match signals
- drop symlink in favor of copy so it works on Windows
- revert because I missed the case of check_ranges being false
- add tests, edge cases where the min/max is way less than signal width
- clean up warning
- add unsigned to the name, add test case
- change signal logic to handle negative factors, add tests
- Bump rustc to latest stable, 1.78
- Merge pull request #68 from projectgus/tweaks/codegen_warnings
- Rename .envrc for non-Nix users, add note in README
- dont assign signed integers to unsigned integers
- Update README
- Fix clippy warnings
- Use checked_sub(offset) for set_signal methods
- Don't treat signals as floats if factor is integer
- Add flag to impl std Error
- Tweak docs and optional features
- Make feature-gated impls configurable
</blockquote>
## `dbc-codegen-cli`
<blockquote>
##
[0.4.0](v0.3.0...v0.4.0) -
2026-09-22
### Added
- [**breaking**] streamline DBC code generation and file writing
([#128](#128))
### Other
- 2024 edition, bump deps, minor fixes
([#196](#196))
- Generate raw signal getters and setters
([#193](#193))
- Support relation attributes in attribute_structs
([#192](#192))
- Generate message size and cycle time consts
([#176](#176))
- Add option to generate typed constants from DBC attributes
([#175](#175))
- cleanup clippy, justfile, and proj cleanup
([#180](#180))
- *(deps)* bump the all-cargo-version-updates group with 2 updates
([#161](#161))
- minor code cleanup
([#114](#114))
- allow generated file to be used with `include!`
([#108](#108))
- OxiBUS onboarding cleanup
([#102](#102))
- run `just fmt` to cleanup imports
([#107](#107))
- Bump the all-cargo-version-updates group across 1 directory with 9
updates ([#106](#106))
- upgrade to can-dbc v8
([#101](#101))
- make debug_prints configurable
- Merge pull request #68 from projectgus/tweaks/codegen_warnings
- Rename .envrc for non-Nix users, add note in README
- Update README
- Make feature-gated impls configurable
</blockquote>
</p></details>
---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).
Adds an option to generate typed constants from DBC
BA_attributes and place them within the existing generated message types. This is useful for DBCs that define per-message or per-signal metadata, like AUTOSAR E2E protection or SecOC parameters.Users define a struct that their crate owns and specify where each field should come from by adding one or more
AttributeStructentries to the generatorConfig. I have created an example to show the syntax in the README.