---
title: "Custom Rust Types"
description: "The Rust SDK works with caller-defined order and execution-report types. Policies depend on capability traits such as HasInstrument, HasTradeAmount."
---

# Custom Rust Types

The Rust SDK works with caller-defined order and execution-report types.
Policies depend on capability traits such as `HasInstrument`, `HasTradeAmount`,
`HasOrderPrice`, `HasPnl`, and `HasFee`, so any type that provides the
required traits can be passed as the `Order` or `ExecutionReport` type
parameter to `Engine::builder::<Order, ExecutionReport, AccountAdjustment>()`.

Two authoring styles are supported:

- manual `Has*` implementations;
- derive-based wrapper composition through `RequestFields`.

## Why Capability Traits Instead of One Giant Record

OpenPit is aimed at latency-sensitive trading code, not one universal
order or report structure that carries every conceivable field. The
capability-trait approach exists so that:

- policies declare only the fields they actually need;
- host applications carry only the data their code path uses;
- custom project fields live next to SDK fields without bloating the core
  model;
- wrapper composition stays cheap and explicit;
- the SDK remains modular instead of centralizing every extension into one
  ever-growing public record type.

In practice this means a policy that only needs `HasTradeAmount` and
`HasOrderPrice` does not force the caller to provide `HasPnl`, `HasFee`,
position fields, or execution-report data just to satisfy a monolithic
model. That is the trade-off: more explicit composition in exchange for
tighter contracts and less unnecessary data.

## Supported Derive Setup

The supported way to use derive macros is through the main crate feature:

```toml
openpit = { version = "X.X", features = ["derive"] }
```

This keeps `openpit` and `openpit-derive` in lockstep and exposes
`RequestFields` from the main crate namespace.

Direct dependency on `openpit-derive` is technically possible, but it is not
the supported integration path.

## Manual Field Implementations

Manual implementations are the most explicit option. They are appropriate when:

- you only need a small number of traits,
- your type layout does not follow the standard wrapper pattern,
- a field requires custom conversion logic.

For optional reference returns or conversions, implement the trait manually.
This is the correct approach for cases such as:

- converting `Option<T>` into `Option<&T>`,
- validating a field before returning it,
- computing a value instead of reading a field directly.

## Derive-Based Wrapper Composition

`RequestFields` reduces boilerplate for wrapper stacks that follow the SDK's
composition style.

Account-adjustment wrappers follow the same composition style as order/report
wrappers.

In this pattern:

- `#[openpit(Trait(method -> ReturnType))]` on a field generates a direct impl
  for that trait,
- `#[openpit(HasSomething(-> ReturnType))]` is the shorthand form when the
  derive can infer the method name from a `Has*` trait,
- `#[openpit(inner, ...)]` marks the passthrough field and generates delegated
  impls for the listed traits.

That means a wrapper can add new fields while preserving all previously
available capabilities from the inner type.

## Selecting the Inner Field

`RequestFields` does not infer passthrough from the field name alone.
Passthrough implementations are generated only for traits listed on a field
marked with `#[openpit(inner, ...)]`.

Without the trait list on the `inner` field, no passthrough impls are
generated.

## Attribute Syntax

`RequestFields` accepts only namespaced `#[openpit(...)]` attributes.
Direct mappings spell the capability trait, method name, and return type.
Inner passthrough mappings add the `inner` marker and list the delegated
capabilities. Legacy `#[request_fields(...)]` syntax is rejected on purpose;
the derive emits a compile-time error that points to `#[openpit(...)]`.

## How Passthrough Works

`RequestFields` is for wrapper composition, not for arbitrary structural
introspection.

The derive generates implementations for the exact trait paths listed in
`#[openpit(...)]`. For direct field mappings it calls the named method on that
field. For `#[openpit(inner, ...)]` mappings it generates passthrough impls with
the corresponding `where InnerType: Trait` bound.

Method inference in the `Trait(-> ReturnType)` form only works for `Has*` trait
names. For any other trait name, spell out the method explicitly.

Compatibility is guaranteed for the supported path where `RequestFields` is
re-exported from `openpit` under the `derive` feature and both crates move in
lockstep.

## Model Example

The runnable [Policy API - Rust Custom Models](Policy-API.md#rust-custom-models)
example demonstrates a minimal manually composed model. This page documents
the separate `RequestFields` and manual capability-trait authoring options; it
does not provide an independent runnable wrapper-composition example.

## Choosing Between Manual and Derive

Prefer manual implementations when:

- the type is not a wrapper,
- field access needs custom logic,
- only one or two traits are needed.

Prefer `RequestFields` when:

- you are building `With*` wrappers,
- you want to compose multiple layers,
- you want trait passthrough through the wrapper stack with minimal boilerplate.

## Related Pages

- [Getting Started](Getting-Started.md): first engine construction and end-to-end flow
- [Architecture](Architecture.md): public SDK surfaces and integration model
- [Custom Go Types](Custom-Go-Types.md): typed Go client payloads
- [Custom Python Types](Custom-Python-Types.md): Python model subclasses
- [Custom JS Types](Custom-JS-Types.md): typed JavaScript policy payloads
- [Custom Cpp Types](Custom-Cpp-Types.md): C++ polymorphic client payloads
