fmi-export 0.1.0

FMU export support for FMI 3.0
Documentation
# fmi-export

[<img alt="github" src="https://img.shields.io/github/stars/jondo2010/rust-fmi?style=for-the-badge&logo=github" height="20">](https://github.com/jondo2010/rust-fmi)
[<img alt="crates.io" src="https://img.shields.io/crates/v/fmi.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/fmi-export)
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-fmi-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/fmi-export)
[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/jondo2010/rust-fmi/ci.yml?branch=main&style=for-the-badge" height="20">](https://github.com/jondo2010/rust-fmi/actions?query=branch%3Amain)

A Rust interface to FMUs (Functional Mockup Units) that follow the FMI Standard. This crate provides necessary interfaces and utilities to construct FMUs.

See [http://www.fmi-standard.org](http://www.fmi-standard.org)

## Quick start: export an FMU

1) Define a `cdylib` model crate and derive `FmuModel`:

```rust,ignore
use fmi_export::FmuModel;

#[derive(FmuModel, Default, Debug)]
struct MyModel {
    #[variable(causality = Output, start = 1.0)]
    y: f64,
}
```

2) Export FMI symbols:

```rust,ignore
fmi_export::export_fmu!(MyModel);
```

3) Bundle the FMU with `xtask`:

```bash
cargo run --package xtask -- --package my-model bundle
```

## Building FMUs

This repository builds FMI 3.0 FMUs from pure Rust code. The FMI API interfacing boilerplate is generated with the
`FmuModel` derive macro. Automated packaging is handled by an `xtask` module.

### Minimal FMU setup

Your FMU crate must:

- Be a `cdylib`:

```toml
[lib]
crate-type = ["cdylib"]
```

- Derive `FmuModel` for your model struct
- Export FMI symbols via `export_fmu!`

Example skeleton:

```rust,ignore
use fmi_export::FmuModel;

#[derive(FmuModel, Default, Debug)]
struct MyModel {
    #[variable(causality = Output, start = 1.0)]
    y: f64,
}

fmi_export::export_fmu!(MyModel);
```

### Build an FMU (this repo)

From the repository root:

```bash
cargo run xtask -- --package can-triggered-output bundle
```

The FMU zip is written to:

```text
target/fmu/<model_identifier>.fmu
```

`<model_identifier>` is the Rust `cdylib` target name (for `can-triggered-output`, this is
`can_triggered_output`).

### Common options

- Build a release FMU:

```bash
cargo run --package xtask -- --package can-triggered-output bundle --release
```

- Build for a specific target:

```bash
cargo run --package xtask -- --package can-triggered-output bundle --target x86_64-unknown-linux-gnu
```

## FmuModel derive reference

### Struct-level attributes

Use `#[model(...)]` on the struct to configure the generated FMI interfaces and
metadata.

```rust,ignore
#[derive(FmuModel, Default)]
#[model(
    description = "Example FMU",
    model_exchange = true,
    co_simulation = false,
    scheduled_execution = false,
    user_model = true,
)]
struct MyModel {
    #[variable(causality = Output, start = 1.0)]
    y: f64,
}
```

Supported keys:

- `description`: Optional string. Defaults to the struct docstring if omitted.
- `model_exchange`: Optional bool. Defaults to `true`.
- `co_simulation`: Optional bool. Defaults to `false`.
- `scheduled_execution`: Optional bool. Defaults to `false`.
- `user_model`: Optional bool. Defaults to `true`. Set `false` to provide your
  own `impl UserModel`.

Notes:

- All boolean flags must be explicit (`co_simulation = true`). Shorthand
  `co_simulation` is rejected.
- `#[model()]` with no arguments is valid and uses the defaults above.

### Field-level attributes

Use `#[variable(...)]` to include a field as an FMI variable. Use `#[alias(...)]`
for additional aliases. Both attributes accept the same keys.

```rust,ignore
#[derive(FmuModel, Default)]
struct MyModel {
    /// Height above ground
    #[variable(causality = Output, start = 1.0)]
    h: f64,

    /// Velocity of the ball
    #[variable(causality = Output, start = 0.0)]
    #[alias(name = "der(h)", causality = Local, derivative = h)]
    v: f64,
}
```

Supported keys for `#[variable(...)]` and `#[alias(...)]`:

- `skip`: Bool. When `true`, the field is ignored for FMI variables.
- `name`: String. Overrides the variable name (defaults to the field name).
- `description`: String. Overrides the field docstring.
- `causality`: One of `Parameter`, `CalculatedParameter`, `Input`, `Output`,
  `Local`, `Independent`, `Dependent`, `StructuralParameter`.
- `variability`: One of `Constant`, `Fixed`, `Tunable`, `Discrete`, `Continuous`.
- `start`: Rust expression used as the start value.
- `initial`: One of `Exact`, `Calculated`, `Approx`.
- `derivative`: Ident referencing another field. Marks this variable as the
  derivative of that field.
- `event_indicator`: Bool. When `true`, counts toward the FMI event indicator
  total.
- `interval_variability`: One of `Constant`, `Fixed`, `Tunable`, `Changing`,
  `Countdown`, `Triggered`.
- `clocks`: List of clock field idents that this variable belongs to.
- `max_size`: Integer. Max size for Binary variables.
- `mime_type`: String. MIME type for Binary variables.

Notes:

- Continuous state variables are inferred by `derivative` relationships.
- `clocks` must reference clock variables in the same model. The generated FMU
  resolves these to value references.

### Child components

Use `#[child(...)]` to reuse another `FmuModel` as a component and prefix its
variable names.

```rust,ignore
#[derive(FmuModel, Default)]
struct Parent {
    #[child(prefix = "bus")]
    bus: CanBus,
}
```

Supported keys:

- `prefix`: Optional string. Defaults to the field name. Child variables are
  named `<parent_prefix><prefix>.<child_variable>`.

Notes:

- Child fields should implement the `Model` trait (typically via `FmuModel`).
- `#[child]` only affects naming and metadata; it does not change runtime
  behavior of the child component.

## License

Licensed under either of

 * Apache License, Version 2.0
   ([LICENSE-APACHE]LICENSE-APACHE or <http://www.apache.org/licenses/LICENSE-2.0>)
 * MIT license
   ([LICENSE-MIT]LICENSE-MIT or <http://opensource.org/licenses/MIT>)

at your option.

## Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.