nautilus_macros/lib.rs
1// -------------------------------------------------------------------------------------------------
2// Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3// https://nautechsystems.io
4//
5// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6// You may not use this file except in compliance with the License.
7// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Procedural macros for Nautilus model and serialization types.
17
18#![warn(clippy::pedantic)]
19#![allow(
20 clippy::assert_is_empty,
21 reason = "`assert!(x.is_empty())` is clearer than comparing against an empty value"
22)]
23
24mod model;
25mod serialization;
26mod support;
27
28use proc_macro::TokenStream;
29
30/// Expands a named-field struct into a Serde-backed custom data type.
31///
32/// Generates the required Serde derives, `HasTsInit`, `CustomDataTrait`, `Data` conversions,
33/// constructor, display implementation, and optional PyO3 bindings. The struct must contain
34/// `ts_event` and `ts_init` fields.
35///
36/// Use `#[custom_data(pyo3)]` to generate Python bindings.
37/// Use `#[custom_data(pyo3, no_display)]` to provide a custom display implementation.
38/// Use `stub_module = "nautilus_trader.<module>"` with `pyo3` to emit stub metadata.
39/// Use `#[custom_data_field(serde)]` for fields requiring the generic Serde Python bridge.
40#[proc_macro_attribute]
41pub fn custom_data(attr: TokenStream, item: TokenStream) -> TokenStream {
42 model::expand_custom_data(attr.into(), item.into()).into()
43}
44
45/// Adds Arrow schema, encoding, and decoding implementations to a custom data struct.
46///
47/// Apply this above `#[nautilus_model::custom_data]` for macro-generated model behavior, or use it
48/// alone when the model traits are implemented manually. Call
49/// `nautilus_serialization::ensure_custom_data_registered::<T>()` before catalog or streaming
50/// serialization.
51///
52/// Supported field types include `InstrumentId`, `AccountId`, `Currency`, `BarType`, `Params`,
53/// `Price`, `Quantity`, `Decimal`, optional prices and quantities, `UnixNanos`, `f64`, `f32`, `bool`,
54/// `String`, `u64`, `i64`, `u32`, `i32`, `Vec<f64>`, and `Vec<u8>`.
55/// Prices and quantities use nullable `Decimal128(38, 16)` columns. `Vec<u8>` is the deliberate
56/// opaque-byte escape hatch for custom schemas.
57/// `Decimal` values preserve their numeric value at scale 16, but not the source value's
58/// trailing-zero scale.
59/// Use `#[custom_data_field(native_enum)]` on a native enum that implements `Display` and
60/// `FromStr` to encode it as a compact dictionary of display names.
61/// Use `#[custom_data_field(serde)]` on a field to store any Serde serializable field as a
62/// Serde JSON-backed Arrow `Utf8` column. Python field access for such fields comes from
63/// `nautilus_model`'s `custom_data` macro, not this macro.
64///
65/// Use `#[arrow_custom_data(pyo3)]` to generate `PyArrow` `encode_record_batch_py` and
66/// `decode_record_batch_py` methods; this is independent from the model macro's `pyo3` option.
67/// Use `stub_module = "nautilus_trader.<module>"` with `pyo3` to emit pyo3-stub-gen metadata.
68#[proc_macro_attribute]
69pub fn arrow_custom_data(attr: TokenStream, item: TokenStream) -> TokenStream {
70 serialization::expand_arrow_custom_data(attr.into(), item.into()).into()
71}