Skip to content

fix: handle duplicate signal names - #126

Merged
nyurik merged 2 commits into
oxibus:mainfrom
nyurik:dups
Jan 23, 2026
Merged

nyurik merged 2 commits into
oxibus:mainfrom
nyurik:dups

Conversation

@nyurik

@nyurik nyurik commented Jan 21, 2026 •

Copy link
Copy Markdown
Member

This PR includes #127 which should be merged first

In a case with duplicate names:

VAL_TABLE_ Bar 6 "reserved" 5 "reserved" 4 "unused 2" 3 "unused" 2 "unused" 1 "#%=*�'" 0 "With space" -5 "A negative value" ;
VAL_ 0 Foo 6 "reserved" 5 "reserved" 4 "unused 2" 3 "unused" 2 "unused" 1 "#%=*�'" 0 "With space" -5 "A negative value" ;

generate parametrized enum instead:

match signal {
    6 => FooFoo::Reserved(6),
    5 => FooFoo::Reserved(5),
    4 => FooFoo::Unused2,
    3 => FooFoo::Unused(3),
    2 => FooFoo::Unused(2),
    1 => FooFoo::XÄ,
    0 => FooFoo::WithSpace,
    -5 => FooFoo::ANegativeValue,
    _ => FooFoo::_Other(self.foo_raw()),
}
  • use appropriate signed type too: u8 -> i8
let signal = self.raw.view_bits::<Lsb0>()[0..8].load_le::<i8>();
  • streamline multiplex indicator handling and enhance enum variant generation

@nyurik

nyurik commented Jan 21, 2026

Copy link
Copy Markdown
Member Author

@rnd-ash does this solve your #98 ?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes code generation issues when DBC files contain duplicate signal names by generating parameterized tuple enum variants instead of duplicate unit variants. When multiple signals have the same description (e.g., "reserved", "unused"), the code now generates a single tuple variant like Reserved(i8) that can hold the actual signal value, eliminating compilation errors from duplicate enum variant names.

Changes:

  • Implemented duplicate detection and tuple variant generation for enum values with identical names
  • Fixed signed integer type usage for signals with negative values
  • Refactored multiplex indicator handling to use imported variants and matches! macro

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/snapshots.rs Removed failing tests from BAD_TESTS list; added manual test function for debugging
tests-snapshots/dbc-cantools/vehicle.snap.stderr Removed compilation errors showing the vehicle.snap.rs file now compiles successfully
tests-snapshots/dbc-cantools/vehicle.snap.rs Updated generated code with tuple variants for duplicate "Unused" names
tests-snapshots/dbc-cantools/issue_199_extended.snap.stderr Removed compilation errors for duplicate "X" variants
tests-snapshots/dbc-cantools/issue_199_extended.snap.rs Updated generated code with tuple variants for duplicate "X" names
tests-snapshots/dbc-cantools/issue_199.snap.stderr Removed compilation errors for duplicate "X" variants
tests-snapshots/dbc-cantools/issue_199.snap.rs Updated generated code with tuple variants for duplicate "X" names
tests-snapshots/dbc-cantools/choices.snap.stderr Removed compilation errors for duplicate enum variants and type mismatches
tests-snapshots/dbc-cantools/choices.snap.rs Updated generated code with i8 type for signed signals and tuple variants for duplicates
src/lib.rs Implemented core logic for duplicate detection, tuple variant generation, and improved multiplex handling
justfile Added test-manual command for running single file debugging tests

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov

codecov Bot commented Jan 21, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.37864% with 13 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/lib.rs 87.37% 0 Missing and 13 partials ⚠️

📢 Thoughts on this report? Let us know!

@rnd-ash

rnd-ash commented Jan 21, 2026 •

Copy link
Copy Markdown

Hey @nyurik ...

I'm trying to test it on the bug reported DBC, but it appears something broke since i last tried this with the DBC parsing

build.rs

let dbc_path = "bug_showcase.dbc";
    let dbc_file_contents = std::fs::read_to_string(dbc_path).unwrap();
    println!("cargo:rerun-if-changed={}", dbc_path);
    File::create("src/can/bug_showcase.rs").unwrap();
    let mut out =
        std::io::BufWriter::new(std::fs::File::create("src/can/bug_showcase.rs").unwrap());

    let config = dbc_codegen::Config::builder()
        .dbc_name("bug_showcase.dbc")
        .dbc_content(&dbc_file_contents)
        .debug_prints(true)
        .build();

    if let Err(e) = dbc_codegen::codegen(config, &mut out) {
        panic!("Error parsing: {e}");
    }
  --- stdout
  cargo:rerun-if-changed=bug_showcase.dbc

  --- stderr

  thread 'main' panicked at build.rs:25:9:
  Error parsing: Could not parse dbc file: Pest(
      Error {
          variant: ParsingError {
              positives: [
                  EOI,
                  env_var,
                  msg_var,
                  version,
                  new_symbols,
                  bit_timing,
                  nodes,
                  comment,
                  attr_def,
                  attr_value,
                  value_table_def,
                  value_table,
                  signal_group,
                  signal_value_type,
                  message_transmitter,
                  ba_def_rel,
                  ba_rel,
                  ba_def_def_rel,
                  ba_def_def,
                  sg_mul_val,
                  env_var_data,
              ],
              negatives: [],
          },
          location: Pos(
              86,
          ),
          line_col: Pos(
              (
                  11,
                  1,
              ),
          ),
          inner: ErrorInner {
              path: None,
              line: "SG_ Test_input_Mux M : 56|4@1+ (1,0) [0|0] \"\" Vector__XXX",
              continued_line: None,
              parse_attempts: None,
          },
      },
  )
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

@nyurik

nyurik commented Jan 21, 2026

Copy link
Copy Markdown
Member Author

@rnd-ash I have switched to the pest-based parser, which gets verified much more extensively than before - it is able to parse every single test case including opendbc files. Are you certain your file uses correct .dbc grammar?

@rnd-ash

rnd-ash commented Jan 21, 2026

Copy link
Copy Markdown

@rnd-ash I have switched to the pest-based parser, which gets verified much more extensively than before - it is able to parse every single test case including opendbc files. Are you certain your file uses correct .dbc grammar?

These DBCs are generated by PCAN tools, so I would have thought they were using correct grammar as well...

@nyurik

nyurik commented Jan 21, 2026

Copy link
Copy Markdown
Member Author

interesting, thx. AI suggested a minor fix to the pest grammar - making spaces in some cases optional. I will make a new release shortly

@tegimeki tegimeki left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good and I think you addressed @rnd-ash's issue

In a case with duplicate names:

```
VAL_TABLE_ Bar 6 "reserved" 5 "reserved" 4 "unused 2" 3 "unused" 2 "unused" 1 "#%=*�'" 0 "With space" -5 "A negative value" ;
VAL_ 0 Foo 6 "reserved" 5 "reserved" 4 "unused 2" 3 "unused" 2 "unused" 1 "#%=*�'" 0 "With space" -5 "A negative value" ;
```

generate parametrized enum instead:

```rust
match signal {
    6 => FooFoo::Reserved(6),
    5 => FooFoo::Reserved(5),
    4 => FooFoo::Unused2,
    3 => FooFoo::Unused(3),
    2 => FooFoo::Unused(2),
    1 => FooFoo::XÄ,
    0 => FooFoo::WithSpace,
    -5 => FooFoo::ANegativeValue,
    _ => FooFoo::_Other(self.foo_raw()),
}
```

* use appropriate signed type too: `u8` -> `i8`

```
let signal = self.raw.view_bits::<Lsb0>()[0..8].load_le::<i8>();
```

* streamline multiplex indicator handling and enhance enum variant generation
@nyurik
nyurik merged commit d7108f1 into oxibus:main Jan 23, 2026
7 checks passed
@nyurik
nyurik deleted the dups branch January 23, 2026 21:06
@nyurik nyurik mentioned this pull request Jan 23, 2026
nyurik added a commit that referenced this pull request Sep 22, 2026
## 🤖 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/).
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.

4 participants