can_tools 2.1.2

Rust editor for CanDatabase. It allows to open and modify CAN database from .dbc and .arxml files.
Documentation
# can_tools

Rust utilities for reading, creating, editing and writing CAN DBC files, with optional AUTOSAR `.arxml` import support.

## Features
- Parse DBC files into an in-memory `CanDatabase` (tolerant to comments, extra spaces, and Windows-1252 encoded files).
- Convert AUTOSAR `.arxml` clusters into `CanDatabase` instances.
- Serialize databases back to DBC text with attributes, comments, value tables, multiplexing, and sender/receiver relations.
- Build a fresh database with sensible defaults for attributes such as bus type, baud rate, and version metadata.
- SlotMap-backed storage with stable keys for nodes, messages, and signals, plus helper lookups and sort utilities.

## Quick start
Add to your `Cargo.toml`:
```toml
can_tools = "2.1.2"
```

Parse a DBC, tweak it, and write it back:
```rust
use can_tools::{parse, save, DatabaseError};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut db = parse::from_dbc_file("input.dbc")?;

    // Access a message by name
    if let Some(msg) = db.get_message_by_name_mut("EngineData") {
        msg.comment = "Edited by can_tools".into();
    }

    // Persist the changes
    save::save_to_file("output.dbc", &db)?;
    Ok(())
}
```

Create a brand new database:
```rust
use can_tools::{create, save, types::database::BusType};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let db = create::new_database("MyDbc", BusType::CanFd, "1.0.0")?;
    save::save_to_file("my.dbc", &db)?;
    Ok(())
}
```

Import AUTOSAR `.arxml`:
```rust
use can_tools::parse;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let databases = parse::from_arxml_file("network.arxml")?;
    println!("Extracted {} CAN clusters", databases.len());
    Ok(())
}
```

Iterate messages, nodes, and signals:
```rust
use can_tools::{parse, types::database::CanDatabase};

fn dump(db: &CanDatabase) {
    println!("Database: {} ({} nodes, {} messages)", db.name, db.nodes.len(), db.messages.len());

    for node in db.iter_nodes() {
        println!("- Node: {}", node.name);
    }

    for msg in db.iter_messages() {
        println!("BO_ {} {} ({} bytes)", msg.id, msg.name, msg.byte_length);
        for sig in msg.signals(db) {
            println!(
                "    SG_ {} [{}|{}] {} {:?}",
                sig.name, sig.bit_start, sig.bit_length, sig.endian, sig.sign
            );
        }
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let db = parse::from_dbc_file("input.dbc")?;
    dump(&db);
    Ok(())
}
```

## Modules at a glance
- `parse`: `from_dbc_file` and `from_arxml_file` entry points for ingestion.
- `save`: `save_to_file` and helpers to serialize a `CanDatabase`.
- `create`: builds a `CanDatabase` pre-populated with canonical attributes.
- `types`: core data structures (`CanDatabase`, `CanMessage`, `CanSignal`, `CanNode`, attributes, errors).
- `core`: internal decoders/encoders for DBC sections (attributes, comments, signals, value tables, etc.).

## Error handling
All public operations return strongly-typed errors (e.g. `DbcParseError`, `DbcSaveError`, `DatabaseError`). Many parsing helpers are resilient: malformed lines are skipped where safe, while structural issues (wrong extensions, I/O errors) bubble up as errors.

## Notes
- DBC files are decoded as Windows-1252 with common German characters transliterated to ASCII.
- Names and lookups are case-insensitive; message IDs are tracked in both decimal and hex.
- Multiplexing is supported (both multiplexer and multiplexed signals), as are value tables and relational attributes (`BU_SG_REL_`, `BU_BO_REL_`).

## License
MIT