@@ -31,7 +31,8 @@ All Rust files must include the standardized copyright header:
31
31
32
32
### Code Formatting
33
33
34
- Import formatting is automatically handled by rustfmt when running ` make format ` . The tool organizes imports into groups (standard library, external crates, local imports) and sorts them alphabetically within each group.
34
+ Import formatting is automatically handled by rustfmt when running ` make format ` .
35
+ The tool organizes imports into groups (standard library, external crates, local imports) and sorts them alphabetically within each group.
35
36
36
37
### Error Handling
37
38
@@ -59,11 +60,128 @@ Use structured error handling patterns consistently:
59
60
60
61
3 . ** Error Propagation** : Use the ` ? ` operator for clean error propagation.
61
62
63
+ ### Attribute Patterns
64
+
65
+ Consistent attribute usage and ordering:
66
+
67
+ ``` rust
68
+ #[repr(C )]
69
+ #[derive(Clone , Copy , Debug , Hash , PartialEq , Eq , PartialOrd , Ord )]
70
+ #[cfg_attr(
71
+ feature = " python" ,
72
+ pyo3:: pyclass(module = " nautilus_trader.core.nautilus_pyo3.model" )
73
+ )]
74
+ pub struct Symbol (Ustr );
75
+ ```
76
+
77
+ For enums with extensive derive attributes:
78
+
79
+ ``` rust
80
+ #[repr(C )]
81
+ #[derive(
82
+ Copy ,
83
+ Clone ,
84
+ Debug ,
85
+ Display ,
86
+ Hash ,
87
+ PartialEq ,
88
+ Eq ,
89
+ PartialOrd ,
90
+ Ord ,
91
+ AsRefStr ,
92
+ FromRepr ,
93
+ EnumIter ,
94
+ EnumString ,
95
+ )]
96
+ #[strum(ascii_case_insensitive)]
97
+ #[strum(serialize_all = " SCREAMING_SNAKE_CASE" )]
98
+ #[cfg_attr(
99
+ feature = " python" ,
100
+ pyo3:: pyclass(eq, eq_int, module = " nautilus_trader.core.nautilus_pyo3.model.enums" )
101
+ )]
102
+ pub enum AccountType {
103
+ /// An account with unleveraged cash assets only.
104
+ Cash = 1 ,
105
+ /// An account which facilitates trading on margin, using account assets as collateral.
106
+ Margin = 2 ,
107
+ }
108
+ ```
109
+
110
+ ### Constructor Patterns
111
+
112
+ Use the ` new() ` vs ` new_checked() ` convention consistently:
113
+
114
+ ``` rust
115
+ /// Creates a new [`Symbol`] instance with correctness checking.
116
+ ///
117
+ /// # Errors
118
+ ///
119
+ /// Returns an error if `value` is not a valid string.
120
+ ///
121
+ /// # Notes
122
+ ///
123
+ /// PyO3 requires a `Result` type for proper error handling and stacktrace printing in Python.
124
+ pub fn new_checked <T : AsRef <str >>(value : T ) -> anyhow :: Result <Self > {
125
+ // Implementation
126
+ }
127
+
128
+ /// Creates a new [`Symbol`] instance.
129
+ ///
130
+ /// # Panics
131
+ ///
132
+ /// Panics if `value` is not a valid string.
133
+ pub fn new <T : AsRef <str >>(value : T ) -> Self {
134
+ Self :: new_checked (value ). expect (FAILED )
135
+ }
136
+ ```
137
+
138
+ Always use the ` FAILED ` constant for ` .expect() ` messages related to correctness checks:
139
+
140
+ ``` rust
141
+ use nautilus_core :: correctness :: FAILED ;
142
+ ```
143
+
144
+ ### Constants and Naming Conventions
145
+
146
+ Use SCREAMING_SNAKE_CASE for constants with descriptive names:
147
+
148
+ ``` rust
149
+ /// Number of nanoseconds in one second.
150
+ pub const NANOSECONDS_IN_SECOND : u64 = 1_000_000_000 ;
151
+
152
+ /// Bar specification for 1-minute last price bars.
153
+ pub const BAR_SPEC_1_MINUTE_LAST : BarSpecification = BarSpecification {
154
+ step : NonZero :: new (1 ). unwrap (),
155
+ aggregation : BarAggregation :: Minute ,
156
+ price_type : PriceType :: Last ,
157
+ };
158
+ ```
159
+
160
+ ### Re-export Patterns
161
+
162
+ Organize re-exports alphabetically and place at the end of lib.rs files:
163
+
164
+ ``` rust
165
+ // Re-exports
166
+ pub use crate :: {
167
+ nanos :: UnixNanos ,
168
+ time :: AtomicTime ,
169
+ uuid :: UUID4 ,
170
+ };
171
+
172
+ // Module-level re-exports
173
+ pub use crate :: identifiers :: {
174
+ account_id :: AccountId ,
175
+ actor_id :: ActorId ,
176
+ client_id :: ClientId ,
177
+ };
178
+ ```
179
+
62
180
### Documentation Standards
63
181
64
182
#### Module-Level Documentation
65
183
66
- All modules should have comprehensive module-level documentation:
184
+ All modules must have module-level documentation starting with a brief description :
67
185
68
186
``` rust
69
187
// ! Functions for correctness checks similar to the *design by contract* philosophy.
@@ -74,6 +192,38 @@ All modules should have comprehensive module-level documentation:
74
192
// ! some section of code - for correct behavior as per the design specification.
75
193
```
76
194
195
+ For modules with feature flags, document them clearly:
196
+
197
+ ``` rust
198
+ // ! # Feature flags
199
+ // !
200
+ // ! This crate provides feature flags to control source code inclusion during compilation,
201
+ // ! depending on the intended use case:
202
+ // !
203
+ // ! - `ffi`: Enables the C foreign function interface (FFI) from [cbindgen](https://github.com/mozilla/cbindgen).
204
+ // ! - `python`: Enables Python bindings from [PyO3](https://pyo3.rs).
205
+ // ! - `stubs`: Enables type stubs for use in testing scenarios.
206
+ ```
207
+
208
+ #### Field Documentation
209
+
210
+ All struct and enum fields must have documentation with terminating periods:
211
+
212
+ ``` rust
213
+ pub struct Currency {
214
+ /// The currency code as an alpha-3 string (e.g., "USD", "EUR").
215
+ pub code : Ustr ,
216
+ /// The currency decimal precision.
217
+ pub precision : u8 ,
218
+ /// The ISO 4217 currency code.
219
+ pub iso4217 : u16 ,
220
+ /// The full name of the currency.
221
+ pub name : Ustr ,
222
+ /// The currency type, indicating its category (e.g. Fiat, Crypto).
223
+ pub currency_type : CurrencyType ,
224
+ }
225
+ ```
226
+
77
227
#### Function Documentation
78
228
79
229
Document all public functions with:
@@ -171,14 +321,23 @@ impl Send for MessageBus {
171
321
172
322
#### Test Organization
173
323
324
+ Use consistent test module structure with section separators:
325
+
174
326
``` rust
327
+ /// /////////////////////////////////////////////////////////////////////////////
328
+ // Tests
329
+ /// /////////////////////////////////////////////////////////////////////////////
175
330
#[cfg(test)]
176
331
mod tests {
177
332
use rstest :: rstest;
178
333
use super :: * ;
179
- use crate :: stubs :: * ;
334
+ use crate :: identifiers :: { Symbol , stubs :: * } ;
180
335
181
- // Tests here
336
+ #[rstest]
337
+ fn test_string_reprs (symbol_eth_perp : Symbol ) {
338
+ assert_eq! (symbol_eth_perp . as_str (), " ETH-PERP" );
339
+ assert_eq! (format! (" {symbol_eth_perp}" ), " ETH-PERP" );
340
+ }
182
341
}
183
342
```
184
343
@@ -188,11 +347,12 @@ Use the `rstest` attribute consistently, and for parameterized tests:
188
347
189
348
``` rust
190
349
#[rstest]
191
- #[case(1)]
192
- #[case(3)]
193
- #[case(5)]
194
- fn test_with_different_periods (#[case ] period : usize ) {
195
- // Test implementation
350
+ #[case(" AUDUSD" , false)]
351
+ #[case(" AUD/USD" , false)]
352
+ #[case(" CL.FUT" , true)]
353
+ fn test_symbol_is_composite (#[case ] input : & str , #[case ] expected : bool ) {
354
+ let symbol = Symbol :: new (input );
355
+ assert_eq! (symbol . is_composite (), expected );
196
356
}
197
357
```
198
358
@@ -203,6 +363,7 @@ Use descriptive test names that explain the scenario:
203
363
``` rust
204
364
fn test_sma_with_no_inputs ()
205
365
fn test_sma_with_single_input ()
366
+ fn test_symbol_is_composite ()
206
367
```
207
368
208
369
## Unsafe Rust
@@ -232,27 +393,6 @@ and covering the invariants which the function expects the callers to uphold, an
232
393
unsafe impl Send for MessageBus {}
233
394
```
234
395
235
- ### File Headers
236
-
237
- All Rust files should include the standard copyright header:
238
-
239
- ``` rust
240
- // -------------------------------------------------------------------------------------------------
241
- // Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
242
- // https://nautechsystems.io
243
- //
244
- // Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
245
- // You may not use this file except in compliance with the License.
246
- // You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
247
- //
248
- // Unless required by applicable law or agreed to in writing, software
249
- // distributed under the License is distributed on an "AS IS" BASIS,
250
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
251
- // See the License for the specific language governing permissions and
252
- // limitations under the License.
253
- // -------------------------------------------------------------------------------------------------`
254
- ```
255
-
256
396
## Tooling Configuration
257
397
258
398
The project uses several tools for code quality:
0 commit comments