Skip to main content

nautilus_model/ffi/
enums.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
16use std::{ffi::c_char, str::FromStr};
17
18use nautilus_core::ffi::{
19    abort_on_panic,
20    string::{cstr_as_str, str_to_cstr},
21};
22use strum::{AsRefStr, Display, EnumString};
23
24use crate::enums::{
25    AccountType, AggregationSource, AggressorSide, AssetClass, BarAggregation, BookAction,
26    BookType, ContingencyType, CurrencyType, InstrumentClass, InstrumentCloseType, LiquiditySide,
27    MarketStatus, MarketStatusAction, OmsType, OptionKind, OrderSide, OrderStatus, OrderType,
28    OtoTriggerMode, PositionAdjustmentType, PositionSide, PriceType, RecordFlag, TimeInForce,
29    TradingState, TrailingOffsetType, TriggerType,
30};
31
32/// The stable zero-inclusive contingency-type representation required by the existing C ABI.
33///
34/// Use [`Option<ContingencyType>`] for ordinary Rust optionality.
35#[repr(C)]
36#[derive(Copy, Clone, Debug, Default, Display, Hash, PartialEq, Eq, AsRefStr, EnumString)]
37#[strum(ascii_case_insensitive)]
38#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
39pub enum ContingencyTypeOptional {
40    /// Compatibility value for no specified contingency type.
41    ///
42    /// This value may be removed in a future version.
43    #[default]
44    NoContingency = 0,
45    /// One-Cancels-the-Other.
46    Oco = 1,
47    /// One-Triggers-the-Other.
48    Oto = 2,
49    /// One-Updates-the-Other.
50    Ouo = 3,
51}
52
53impl ContingencyTypeOptional {
54    #[must_use]
55    pub const fn as_option(self) -> Option<ContingencyType> {
56        match self {
57            Self::NoContingency => None,
58            Self::Oco => Some(ContingencyType::Oco),
59            Self::Oto => Some(ContingencyType::Oto),
60            Self::Ouo => Some(ContingencyType::Ouo),
61        }
62    }
63}
64
65impl From<Option<ContingencyType>> for ContingencyTypeOptional {
66    fn from(value: Option<ContingencyType>) -> Self {
67        match value {
68            None => Self::NoContingency,
69            Some(ContingencyType::Oco) => Self::Oco,
70            Some(ContingencyType::Oto) => Self::Oto,
71            Some(ContingencyType::Ouo) => Self::Ouo,
72        }
73    }
74}
75
76/// The stable zero-inclusive order-side representation required by the existing C ABI.
77///
78/// Use [`Option<OrderSide>`] for ordinary Rust optionality.
79#[repr(C)]
80#[derive(Copy, Clone, Debug, Default, Display, Hash, PartialEq, Eq, AsRefStr, EnumString)]
81#[strum(ascii_case_insensitive)]
82#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
83pub enum OrderSideOptional {
84    /// Compatibility value for no specified order side.
85    ///
86    /// This value may be removed in a future version.
87    #[default]
88    NoOrderSide = 0,
89    /// The order is a BUY.
90    Buy = 1,
91    /// The order is a SELL.
92    Sell = 2,
93}
94
95impl OrderSideOptional {
96    #[must_use]
97    pub const fn as_option(self) -> Option<OrderSide> {
98        match self {
99            Self::NoOrderSide => None,
100            Self::Buy => Some(OrderSide::Buy),
101            Self::Sell => Some(OrderSide::Sell),
102        }
103    }
104}
105
106impl From<Option<OrderSide>> for OrderSideOptional {
107    fn from(value: Option<OrderSide>) -> Self {
108        match value {
109            None => Self::NoOrderSide,
110            Some(OrderSide::Buy) => Self::Buy,
111            Some(OrderSide::Sell) => Self::Sell,
112        }
113    }
114}
115
116/// The stable zero-inclusive position-side representation required by the existing C ABI.
117///
118/// Use [`Option<PositionSide>`] for ordinary Rust optionality.
119#[repr(C)]
120#[derive(Copy, Clone, Debug, Default, Display, Hash, PartialEq, Eq, AsRefStr, EnumString)]
121#[strum(ascii_case_insensitive)]
122#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
123pub enum PositionSideOptional {
124    /// Compatibility value for no specified position side.
125    ///
126    /// This value may be removed in a future version.
127    #[default]
128    NoPositionSide = 0,
129    /// A neutral/flat position.
130    Flat = 1,
131    /// A long position.
132    Long = 2,
133    /// A short position.
134    Short = 3,
135}
136
137impl PositionSideOptional {
138    #[must_use]
139    pub const fn as_option(self) -> Option<PositionSide> {
140        match self {
141            Self::NoPositionSide => None,
142            Self::Flat => Some(PositionSide::Flat),
143            Self::Long => Some(PositionSide::Long),
144            Self::Short => Some(PositionSide::Short),
145        }
146    }
147}
148
149impl From<Option<PositionSide>> for PositionSideOptional {
150    fn from(value: Option<PositionSide>) -> Self {
151        match value {
152            None => Self::NoPositionSide,
153            Some(PositionSide::Flat) => Self::Flat,
154            Some(PositionSide::Long) => Self::Long,
155            Some(PositionSide::Short) => Self::Short,
156        }
157    }
158}
159
160/// The stable zero-inclusive trailing-offset-type representation required by the existing C ABI.
161///
162/// Use [`Option<TrailingOffsetType>`] for ordinary Rust optionality.
163#[repr(C)]
164#[derive(Copy, Clone, Debug, Default, Display, Hash, PartialEq, Eq, AsRefStr, EnumString)]
165#[strum(ascii_case_insensitive)]
166#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
167pub enum TrailingOffsetTypeOptional {
168    /// Compatibility value for no specified trailing offset type.
169    ///
170    /// This value may be removed in a future version.
171    #[default]
172    NoTrailingOffset = 0,
173    /// The trailing offset is based on a market price.
174    Price = 1,
175    /// The trailing offset is based on basis points.
176    BasisPoints = 2,
177    /// The trailing offset is based on ticks.
178    Ticks = 3,
179    /// The trailing offset is based on a venue-defined price tier.
180    PriceTier = 4,
181}
182
183impl TrailingOffsetTypeOptional {
184    #[must_use]
185    pub const fn as_option(self) -> Option<TrailingOffsetType> {
186        match self {
187            Self::NoTrailingOffset => None,
188            Self::Price => Some(TrailingOffsetType::Price),
189            Self::BasisPoints => Some(TrailingOffsetType::BasisPoints),
190            Self::Ticks => Some(TrailingOffsetType::Ticks),
191            Self::PriceTier => Some(TrailingOffsetType::PriceTier),
192        }
193    }
194}
195
196impl From<Option<TrailingOffsetType>> for TrailingOffsetTypeOptional {
197    fn from(value: Option<TrailingOffsetType>) -> Self {
198        match value {
199            None => Self::NoTrailingOffset,
200            Some(TrailingOffsetType::Price) => Self::Price,
201            Some(TrailingOffsetType::BasisPoints) => Self::BasisPoints,
202            Some(TrailingOffsetType::Ticks) => Self::Ticks,
203            Some(TrailingOffsetType::PriceTier) => Self::PriceTier,
204        }
205    }
206}
207
208/// The stable zero-inclusive trigger-type representation required by the existing C ABI.
209///
210/// Use [`Option<TriggerType>`] for ordinary Rust optionality.
211#[repr(C)]
212#[derive(Copy, Clone, Debug, Default, Display, Hash, PartialEq, Eq, AsRefStr, EnumString)]
213#[strum(ascii_case_insensitive)]
214#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
215pub enum TriggerTypeOptional {
216    /// Compatibility value for no specified trigger type.
217    ///
218    /// This value may be removed in a future version.
219    #[default]
220    NoTrigger = 0,
221    /// The venue default trigger type.
222    Default = 1,
223    /// The last traded price.
224    LastPrice = 2,
225    /// The mark price.
226    MarkPrice = 3,
227    /// The index price.
228    IndexPrice = 4,
229    /// The bid or ask price.
230    BidAsk = 5,
231    /// Two consecutive last prices.
232    DoubleLast = 6,
233    /// Two consecutive bid or ask prices.
234    DoubleBidAsk = 7,
235    /// The last price or bid or ask price.
236    LastOrBidAsk = 8,
237    /// The midpoint price.
238    MidPoint = 9,
239}
240
241impl TriggerTypeOptional {
242    #[must_use]
243    pub const fn as_option(self) -> Option<TriggerType> {
244        match self {
245            Self::NoTrigger => None,
246            Self::Default => Some(TriggerType::Default),
247            Self::LastPrice => Some(TriggerType::LastPrice),
248            Self::MarkPrice => Some(TriggerType::MarkPrice),
249            Self::IndexPrice => Some(TriggerType::IndexPrice),
250            Self::BidAsk => Some(TriggerType::BidAsk),
251            Self::DoubleLast => Some(TriggerType::DoubleLast),
252            Self::DoubleBidAsk => Some(TriggerType::DoubleBidAsk),
253            Self::LastOrBidAsk => Some(TriggerType::LastOrBidAsk),
254            Self::MidPoint => Some(TriggerType::MidPoint),
255        }
256    }
257}
258
259impl From<Option<TriggerType>> for TriggerTypeOptional {
260    fn from(value: Option<TriggerType>) -> Self {
261        match value {
262            None => Self::NoTrigger,
263            Some(TriggerType::Default) => Self::Default,
264            Some(TriggerType::LastPrice) => Self::LastPrice,
265            Some(TriggerType::MarkPrice) => Self::MarkPrice,
266            Some(TriggerType::IndexPrice) => Self::IndexPrice,
267            Some(TriggerType::BidAsk) => Self::BidAsk,
268            Some(TriggerType::DoubleLast) => Self::DoubleLast,
269            Some(TriggerType::DoubleBidAsk) => Self::DoubleBidAsk,
270            Some(TriggerType::LastOrBidAsk) => Self::LastOrBidAsk,
271            Some(TriggerType::MidPoint) => Self::MidPoint,
272        }
273    }
274}
275
276#[unsafe(no_mangle)]
277pub extern "C" fn account_type_to_cstr(value: AccountType) -> *const c_char {
278    str_to_cstr(value.as_ref())
279}
280
281/// Returns an enum from a C string.
282///
283/// # Safety
284///
285/// Assumes `ptr` is a valid C string pointer.
286///
287/// # Panics
288///
289/// Panics if the C string does not correspond to a valid `AccountType` variant.
290#[unsafe(no_mangle)]
291pub unsafe extern "C" fn account_type_from_cstr(ptr: *const c_char) -> AccountType {
292    abort_on_panic(|| {
293        let value = unsafe { cstr_as_str(ptr) };
294        AccountType::from_str(value)
295            .unwrap_or_else(|_| panic!("invalid `AccountType` enum string value, was '{value}'"))
296    })
297}
298
299#[unsafe(no_mangle)]
300pub extern "C" fn aggregation_source_to_cstr(value: AggregationSource) -> *const c_char {
301    str_to_cstr(value.as_ref())
302}
303
304/// Returns an enum from a C string.
305///
306/// # Safety
307///
308/// Assumes `ptr` is a valid C string pointer.
309///
310/// # Panics
311///
312/// Panics if the C string does not correspond to a valid `AggregationSource` variant.
313#[unsafe(no_mangle)]
314pub unsafe extern "C" fn aggregation_source_from_cstr(ptr: *const c_char) -> AggregationSource {
315    abort_on_panic(|| {
316        let value = unsafe { cstr_as_str(ptr) };
317        AggregationSource::from_str(value).unwrap_or_else(|_| {
318            panic!("invalid `AggregationSource` enum string value, was '{value}'")
319        })
320    })
321}
322
323#[unsafe(no_mangle)]
324pub extern "C" fn aggressor_side_to_cstr(value: AggressorSide) -> *const c_char {
325    str_to_cstr(value.as_ref())
326}
327
328/// Returns an enum from a C string.
329///
330/// # Safety
331///
332/// Assumes `ptr` is a valid C string pointer.
333///
334/// # Panics
335///
336/// Panics if the C string does not correspond to a valid `AggressorSide` variant.
337#[unsafe(no_mangle)]
338pub unsafe extern "C" fn aggressor_side_from_cstr(ptr: *const c_char) -> AggressorSide {
339    abort_on_panic(|| {
340        let value = unsafe { cstr_as_str(ptr) };
341        AggressorSide::from_str(value)
342            .unwrap_or_else(|_| panic!("invalid `AggressorSide` enum string value, was '{value}'"))
343    })
344}
345
346#[unsafe(no_mangle)]
347pub extern "C" fn asset_class_to_cstr(value: AssetClass) -> *const c_char {
348    str_to_cstr(value.as_ref())
349}
350
351/// Returns an enum from a C string.
352///
353/// # Safety
354///
355/// Assumes `ptr` is a valid C string pointer.
356///
357/// # Panics
358///
359/// Panics if the C string does not correspond to a valid `AssetClass` variant.
360#[unsafe(no_mangle)]
361pub unsafe extern "C" fn asset_class_from_cstr(ptr: *const c_char) -> AssetClass {
362    abort_on_panic(|| {
363        let value = unsafe { cstr_as_str(ptr) };
364        AssetClass::from_str(value)
365            .unwrap_or_else(|_| panic!("invalid `AssetClass` enum string value, was '{value}'"))
366    })
367}
368
369#[unsafe(no_mangle)]
370pub extern "C" fn instrument_class_to_cstr(value: InstrumentClass) -> *const c_char {
371    str_to_cstr(value.as_ref())
372}
373
374/// Returns an enum from a C string.
375///
376/// # Safety
377///
378/// Assumes `ptr` is a valid C string pointer.
379///
380/// # Panics
381///
382/// Panics if the C string does not correspond to a valid `InstrumentClass` variant.
383#[unsafe(no_mangle)]
384pub unsafe extern "C" fn instrument_class_from_cstr(ptr: *const c_char) -> InstrumentClass {
385    abort_on_panic(|| {
386        let value = unsafe { cstr_as_str(ptr) };
387        InstrumentClass::from_str(value).unwrap_or_else(|_| {
388            panic!("invalid `InstrumentClass` enum string value, was '{value}'")
389        })
390    })
391}
392
393#[unsafe(no_mangle)]
394pub extern "C" fn bar_aggregation_to_cstr(value: BarAggregation) -> *const c_char {
395    str_to_cstr(value.as_ref())
396}
397
398/// Returns an enum from a C string.
399///
400/// # Safety
401///
402/// Assumes `ptr` is a valid C string pointer.
403///
404/// # Panics
405///
406/// Panics if the C string does not correspond to a valid `BarAggregation` variant.
407#[unsafe(no_mangle)]
408pub unsafe extern "C" fn bar_aggregation_from_cstr(ptr: *const c_char) -> BarAggregation {
409    abort_on_panic(|| {
410        let value = unsafe { cstr_as_str(ptr) };
411        BarAggregation::from_str(value)
412            .unwrap_or_else(|_| panic!("invalid `BarAggregation` enum string value, was '{value}'"))
413    })
414}
415
416#[unsafe(no_mangle)]
417pub extern "C" fn book_action_to_cstr(value: BookAction) -> *const c_char {
418    str_to_cstr(value.as_ref())
419}
420
421/// Returns an enum from a C string.
422///
423/// # Safety
424///
425/// Assumes `ptr` is a valid C string pointer.
426///
427/// # Panics
428///
429/// Panics if the C string does not correspond to a valid `BookAction` variant.
430#[unsafe(no_mangle)]
431pub unsafe extern "C" fn book_action_from_cstr(ptr: *const c_char) -> BookAction {
432    abort_on_panic(|| {
433        let value = unsafe { cstr_as_str(ptr) };
434        BookAction::from_str(value)
435            .unwrap_or_else(|_| panic!("invalid `BookAction` enum string value, was '{value}'"))
436    })
437}
438
439#[unsafe(no_mangle)]
440pub extern "C" fn book_type_to_cstr(value: BookType) -> *const c_char {
441    str_to_cstr(value.as_ref())
442}
443
444/// Returns an enum from a C string.
445///
446/// # Safety
447///
448/// Assumes `ptr` is a valid C string pointer.
449///
450/// # Panics
451///
452/// Panics if the C string does not correspond to a valid `BookType` variant.
453#[unsafe(no_mangle)]
454pub unsafe extern "C" fn book_type_from_cstr(ptr: *const c_char) -> BookType {
455    abort_on_panic(|| {
456        let value = unsafe { cstr_as_str(ptr) };
457        BookType::from_str(value)
458            .unwrap_or_else(|_| panic!("invalid `BookType` enum string value, was '{value}'"))
459    })
460}
461
462#[unsafe(no_mangle)]
463pub extern "C" fn contingency_type_to_cstr(value: ContingencyTypeOptional) -> *const c_char {
464    str_to_cstr(value.as_ref())
465}
466
467/// Returns an enum from a C string.
468///
469/// # Safety
470///
471/// Assumes `ptr` is a valid C string pointer.
472///
473/// # Panics
474///
475/// Panics if the C string does not correspond to a valid `ContingencyTypeOptional` variant.
476#[unsafe(no_mangle)]
477pub unsafe extern "C" fn contingency_type_from_cstr(ptr: *const c_char) -> ContingencyTypeOptional {
478    abort_on_panic(|| {
479        let value = unsafe { cstr_as_str(ptr) };
480        ContingencyTypeOptional::from_str(value).unwrap_or_else(|_| {
481            panic!("invalid `ContingencyTypeOptional` enum string value, was '{value}'")
482        })
483    })
484}
485
486#[unsafe(no_mangle)]
487pub extern "C" fn currency_type_to_cstr(value: CurrencyType) -> *const c_char {
488    str_to_cstr(value.as_ref())
489}
490
491/// Returns an enum from a C string.
492///
493/// # Safety
494///
495/// Assumes `ptr` is a valid C string pointer.
496///
497/// # Panics
498///
499/// Panics if the C string does not correspond to a valid `CurrencyType` variant.
500#[unsafe(no_mangle)]
501pub unsafe extern "C" fn currency_type_from_cstr(ptr: *const c_char) -> CurrencyType {
502    abort_on_panic(|| {
503        let value = unsafe { cstr_as_str(ptr) };
504        CurrencyType::from_str(value)
505            .unwrap_or_else(|_| panic!("invalid `CurrencyType` enum string value, was '{value}'"))
506    })
507}
508
509/// Returns an enum from a C string.
510///
511/// # Safety
512///
513/// Assumes `ptr` is a valid C string pointer.
514///
515/// # Panics
516///
517/// Panics if the C string does not correspond to a valid `InstrumentCloseType` variant.
518#[unsafe(no_mangle)]
519pub unsafe extern "C" fn instrument_close_type_from_cstr(
520    ptr: *const c_char,
521) -> InstrumentCloseType {
522    abort_on_panic(|| {
523        let value = unsafe { cstr_as_str(ptr) };
524        InstrumentCloseType::from_str(value).unwrap_or_else(|_| {
525            panic!("invalid `InstrumentCloseType` enum string value, was '{value}'")
526        })
527    })
528}
529
530#[unsafe(no_mangle)]
531pub extern "C" fn instrument_close_type_to_cstr(value: InstrumentCloseType) -> *const c_char {
532    str_to_cstr(value.as_ref())
533}
534
535#[unsafe(no_mangle)]
536pub extern "C" fn liquidity_side_to_cstr(value: LiquiditySide) -> *const c_char {
537    str_to_cstr(value.as_ref())
538}
539
540/// Returns an enum from a C string.
541///
542/// # Safety
543///
544/// Assumes `ptr` is a valid C string pointer.
545///
546/// # Panics
547///
548/// Panics if the C string does not correspond to a valid `LiquiditySide` variant.
549#[unsafe(no_mangle)]
550pub unsafe extern "C" fn liquidity_side_from_cstr(ptr: *const c_char) -> LiquiditySide {
551    abort_on_panic(|| {
552        let value = unsafe { cstr_as_str(ptr) };
553        LiquiditySide::from_str(value)
554            .unwrap_or_else(|_| panic!("invalid `LiquiditySide` enum string value, was '{value}'"))
555    })
556}
557
558#[unsafe(no_mangle)]
559pub extern "C" fn market_status_to_cstr(value: MarketStatus) -> *const c_char {
560    str_to_cstr(value.as_ref())
561}
562
563/// Returns an enum from a C string.
564///
565/// # Safety
566///
567/// Assumes `ptr` is a valid C string pointer.
568///
569/// # Panics
570///
571/// Panics if the C string does not correspond to a valid `MarketStatus` variant.
572#[unsafe(no_mangle)]
573pub unsafe extern "C" fn market_status_from_cstr(ptr: *const c_char) -> MarketStatus {
574    abort_on_panic(|| {
575        let value = unsafe { cstr_as_str(ptr) };
576        MarketStatus::from_str(value)
577            .unwrap_or_else(|_| panic!("invalid `MarketStatus` enum string value, was '{value}'"))
578    })
579}
580
581#[unsafe(no_mangle)]
582pub extern "C" fn market_status_action_to_cstr(value: MarketStatusAction) -> *const c_char {
583    str_to_cstr(value.as_ref())
584}
585
586/// Returns an enum from a C string.
587///
588/// # Safety
589///
590/// Assumes `ptr` is a valid C string pointer.
591///
592/// # Panics
593///
594/// Panics if the C string does not correspond to a valid `MarketStatusAction` variant.
595#[unsafe(no_mangle)]
596pub unsafe extern "C" fn market_status_action_from_cstr(ptr: *const c_char) -> MarketStatusAction {
597    abort_on_panic(|| {
598        let value = unsafe { cstr_as_str(ptr) };
599        MarketStatusAction::from_str(value).unwrap_or_else(|_| {
600            panic!("invalid `MarketStatusAction` enum string value, was '{value}'")
601        })
602    })
603}
604
605#[unsafe(no_mangle)]
606pub extern "C" fn oms_type_to_cstr(value: OmsType) -> *const c_char {
607    str_to_cstr(value.as_ref())
608}
609
610/// Returns an enum from a C string.
611///
612/// # Safety
613///
614/// Assumes `ptr` is a valid C string pointer.
615///
616/// # Panics
617///
618/// Panics if the C string does not correspond to a valid `OmsType` variant.
619#[unsafe(no_mangle)]
620pub unsafe extern "C" fn oms_type_from_cstr(ptr: *const c_char) -> OmsType {
621    abort_on_panic(|| {
622        let value = unsafe { cstr_as_str(ptr) };
623        OmsType::from_str(value)
624            .unwrap_or_else(|_| panic!("invalid `OmsType` enum string value, was '{value}'"))
625    })
626}
627
628#[unsafe(no_mangle)]
629pub extern "C" fn option_kind_to_cstr(value: OptionKind) -> *const c_char {
630    str_to_cstr(value.as_ref())
631}
632
633/// Returns an enum from a C string.
634///
635/// # Safety
636///
637/// Assumes `ptr` is a valid C string pointer.
638///
639/// # Panics
640///
641/// Panics if the C string does not correspond to a valid `OptionKind` variant.
642#[unsafe(no_mangle)]
643pub unsafe extern "C" fn option_kind_from_cstr(ptr: *const c_char) -> OptionKind {
644    abort_on_panic(|| {
645        let value = unsafe { cstr_as_str(ptr) };
646        OptionKind::from_str(value)
647            .unwrap_or_else(|_| panic!("invalid `OptionKind` enum string value, was '{value}'"))
648    })
649}
650
651#[unsafe(no_mangle)]
652pub extern "C" fn oto_trigger_mode_to_cstr(value: OtoTriggerMode) -> *const c_char {
653    str_to_cstr(value.as_ref())
654}
655
656/// Returns an enum from a C string.
657///
658/// # Safety
659///
660/// Assumes `ptr` is a valid C string pointer.
661///
662/// # Panics
663///
664/// Panics if the C string does not correspond to a valid `OtoTriggerMode` variant.
665#[unsafe(no_mangle)]
666pub unsafe extern "C" fn oto_trigger_mode_from_cstr(ptr: *const c_char) -> OtoTriggerMode {
667    abort_on_panic(|| {
668        let value = unsafe { cstr_as_str(ptr) };
669        OtoTriggerMode::from_str(value)
670            .unwrap_or_else(|_| panic!("invalid `OtoTriggerMode` enum string value, was '{value}'"))
671    })
672}
673
674#[unsafe(no_mangle)]
675pub extern "C" fn order_side_to_cstr(value: OrderSideOptional) -> *const c_char {
676    str_to_cstr(value.as_ref())
677}
678
679/// Returns an enum from a C string.
680///
681/// # Safety
682///
683/// Assumes `ptr` is a valid C string pointer.
684///
685/// # Panics
686///
687/// Panics if the C string does not correspond to a valid `OrderSideOptional` variant.
688#[unsafe(no_mangle)]
689pub unsafe extern "C" fn order_side_from_cstr(ptr: *const c_char) -> OrderSideOptional {
690    abort_on_panic(|| {
691        let value = unsafe { cstr_as_str(ptr) };
692        OrderSideOptional::from_str(value).unwrap_or_else(|_| {
693            panic!("invalid `OrderSideOptional` enum string value, was '{value}'")
694        })
695    })
696}
697
698#[unsafe(no_mangle)]
699pub extern "C" fn order_status_to_cstr(value: OrderStatus) -> *const c_char {
700    str_to_cstr(value.as_ref())
701}
702
703/// Returns an enum from a C string.
704///
705/// # Safety
706///
707/// Assumes `ptr` is a valid C string pointer.
708///
709/// # Panics
710///
711/// Panics if the C string does not correspond to a valid `OrderStatus` variant.
712#[unsafe(no_mangle)]
713pub unsafe extern "C" fn order_status_from_cstr(ptr: *const c_char) -> OrderStatus {
714    abort_on_panic(|| {
715        let value = unsafe { cstr_as_str(ptr) };
716        OrderStatus::from_str(value)
717            .unwrap_or_else(|_| panic!("invalid `OrderStatus` enum string value, was '{value}'"))
718    })
719}
720
721#[unsafe(no_mangle)]
722pub extern "C" fn order_type_to_cstr(value: OrderType) -> *const c_char {
723    str_to_cstr(value.as_ref())
724}
725
726/// Returns an enum from a C string.
727///
728/// # Safety
729///
730/// Assumes `ptr` is a valid C string pointer.
731///
732/// # Panics
733///
734/// Panics if the C string does not correspond to a valid `OrderType` variant.
735#[unsafe(no_mangle)]
736pub unsafe extern "C" fn order_type_from_cstr(ptr: *const c_char) -> OrderType {
737    abort_on_panic(|| {
738        let value = unsafe { cstr_as_str(ptr) };
739        OrderType::from_str(value)
740            .unwrap_or_else(|_| panic!("invalid `OrderType` enum string value, was '{value}'"))
741    })
742}
743
744#[unsafe(no_mangle)]
745pub extern "C" fn position_side_to_cstr(value: PositionSideOptional) -> *const c_char {
746    str_to_cstr(value.as_ref())
747}
748
749/// Returns an enum from a C string.
750///
751/// # Safety
752///
753/// Assumes `ptr` is a valid C string pointer.
754///
755/// # Panics
756///
757/// Panics if the C string does not correspond to a valid `PositionSideOptional` variant.
758#[unsafe(no_mangle)]
759pub unsafe extern "C" fn position_side_from_cstr(ptr: *const c_char) -> PositionSideOptional {
760    abort_on_panic(|| {
761        let value = unsafe { cstr_as_str(ptr) };
762        PositionSideOptional::from_str(value).unwrap_or_else(|_| {
763            panic!("invalid `PositionSideOptional` enum string value, was '{value}'")
764        })
765    })
766}
767
768#[unsafe(no_mangle)]
769pub extern "C" fn position_adjustment_type_to_cstr(value: PositionAdjustmentType) -> *const c_char {
770    str_to_cstr(value.as_ref())
771}
772
773/// Returns an enum from a C string.
774///
775/// # Safety
776///
777/// Assumes `ptr` is a valid C string pointer.
778///
779/// # Panics
780///
781/// Panics if the C string does not correspond to a valid `PositionAdjustmentType` variant.
782#[unsafe(no_mangle)]
783pub unsafe extern "C" fn position_adjustment_type_from_cstr(
784    ptr: *const c_char,
785) -> PositionAdjustmentType {
786    abort_on_panic(|| {
787        let value = unsafe { cstr_as_str(ptr) };
788        PositionAdjustmentType::from_str(value).unwrap_or_else(|_| {
789            panic!("invalid `PositionAdjustmentType` enum string value, was '{value}'")
790        })
791    })
792}
793
794#[unsafe(no_mangle)]
795pub extern "C" fn price_type_to_cstr(value: PriceType) -> *const c_char {
796    str_to_cstr(value.as_ref())
797}
798
799/// Returns an enum from a C string.
800///
801/// # Safety
802///
803/// Assumes `ptr` is a valid C string pointer.
804///
805/// # Panics
806///
807/// Panics if the C string does not correspond to a valid `PriceType` variant.
808#[unsafe(no_mangle)]
809pub unsafe extern "C" fn price_type_from_cstr(ptr: *const c_char) -> PriceType {
810    abort_on_panic(|| {
811        let value = unsafe { cstr_as_str(ptr) };
812        PriceType::from_str(value)
813            .unwrap_or_else(|_| panic!("invalid `PriceType` enum string value, was '{value}'"))
814    })
815}
816
817#[unsafe(no_mangle)]
818pub extern "C" fn record_flag_to_cstr(value: RecordFlag) -> *const c_char {
819    str_to_cstr(value.as_ref())
820}
821
822/// Returns an enum from a C string.
823///
824/// # Safety
825///
826/// Assumes `ptr` is a valid C string pointer.
827///
828/// # Panics
829///
830/// Panics if the C string does not correspond to a valid `RecordFlag` variant.
831#[unsafe(no_mangle)]
832pub unsafe extern "C" fn record_flag_from_cstr(ptr: *const c_char) -> RecordFlag {
833    abort_on_panic(|| {
834        let value = unsafe { cstr_as_str(ptr) };
835        RecordFlag::from_str(value)
836            .unwrap_or_else(|_| panic!("invalid `RecordFlag` enum string value, was '{value}'"))
837    })
838}
839
840#[unsafe(no_mangle)]
841pub extern "C" fn time_in_force_to_cstr(value: TimeInForce) -> *const c_char {
842    str_to_cstr(value.as_ref())
843}
844
845/// Returns an enum from a C string.
846///
847/// # Safety
848///
849/// Assumes `ptr` is a valid C string pointer.
850///
851/// # Panics
852///
853/// Panics if the C string does not correspond to a valid `TimeInForce` variant.
854#[unsafe(no_mangle)]
855pub unsafe extern "C" fn time_in_force_from_cstr(ptr: *const c_char) -> TimeInForce {
856    abort_on_panic(|| {
857        let value = unsafe { cstr_as_str(ptr) };
858        TimeInForce::from_str(value)
859            .unwrap_or_else(|_| panic!("invalid `TimeInForce` enum string value, was '{value}'"))
860    })
861}
862
863#[unsafe(no_mangle)]
864pub extern "C" fn trading_state_to_cstr(value: TradingState) -> *const c_char {
865    str_to_cstr(value.as_ref())
866}
867
868/// Returns an enum from a C string.
869///
870/// # Safety
871///
872/// Assumes `ptr` is a valid C string pointer.
873///
874/// # Panics
875///
876/// Panics if the C string does not correspond to a valid `TradingState` variant.
877#[unsafe(no_mangle)]
878pub unsafe extern "C" fn trading_state_from_cstr(ptr: *const c_char) -> TradingState {
879    abort_on_panic(|| {
880        let value = unsafe { cstr_as_str(ptr) };
881        TradingState::from_str(value)
882            .unwrap_or_else(|_| panic!("invalid `TradingState` enum string value, was '{value}'"))
883    })
884}
885
886#[unsafe(no_mangle)]
887pub extern "C" fn trailing_offset_type_to_cstr(value: TrailingOffsetTypeOptional) -> *const c_char {
888    str_to_cstr(value.as_ref())
889}
890
891/// Returns an enum from a C string.
892///
893/// # Safety
894///
895/// Assumes `ptr` is a valid C string pointer.
896///
897/// # Panics
898///
899/// Panics if the C string does not correspond to a valid `TrailingOffsetTypeOptional` variant.
900#[unsafe(no_mangle)]
901pub unsafe extern "C" fn trailing_offset_type_from_cstr(
902    ptr: *const c_char,
903) -> TrailingOffsetTypeOptional {
904    abort_on_panic(|| {
905        let value = unsafe { cstr_as_str(ptr) };
906        TrailingOffsetTypeOptional::from_str(value).unwrap_or_else(|_| {
907            panic!("invalid `TrailingOffsetTypeOptional` enum string value, was '{value}'")
908        })
909    })
910}
911
912#[unsafe(no_mangle)]
913pub extern "C" fn trigger_type_to_cstr(value: TriggerTypeOptional) -> *const c_char {
914    str_to_cstr(value.as_ref())
915}
916
917/// Returns an enum from a C string.
918///
919/// # Safety
920///
921/// Assumes `ptr` is a valid C string pointer.
922///
923/// # Panics
924///
925/// Panics if the C string does not correspond to a valid `TriggerTypeOptional` variant.
926#[unsafe(no_mangle)]
927pub unsafe extern "C" fn trigger_type_from_cstr(ptr: *const c_char) -> TriggerTypeOptional {
928    abort_on_panic(|| {
929        let value = unsafe { cstr_as_str(ptr) };
930        TriggerTypeOptional::from_str(value).unwrap_or_else(|_| {
931            panic!("invalid `TriggerTypeOptional` enum string value, was '{value}'")
932        })
933    })
934}
935
936#[cfg(test)]
937mod tests {
938    use rstest::rstest;
939
940    use super::*;
941    use crate::enums::OrderSide;
942
943    #[rstest]
944    fn test_name() {
945        assert_eq!(OrderSideOptional::NoOrderSide.as_ref(), "NO_ORDER_SIDE");
946        assert_eq!(OrderSide::Buy.as_ref(), "BUY");
947        assert_eq!(OrderSide::Sell.as_ref(), "SELL");
948    }
949
950    #[rstest]
951    fn test_value() {
952        assert_eq!(OrderSideOptional::NoOrderSide as u8, 0);
953        assert_eq!(OrderSide::Buy as u8, 1);
954        assert_eq!(OrderSide::Sell as u8, 2);
955    }
956
957    #[rstest]
958    #[case(None, ContingencyTypeOptional::NoContingency, 0)]
959    #[case(Some(ContingencyType::Oco), ContingencyTypeOptional::Oco, 1)]
960    #[case(Some(ContingencyType::Oto), ContingencyTypeOptional::Oto, 2)]
961    #[case(Some(ContingencyType::Ouo), ContingencyTypeOptional::Ouo, 3)]
962    fn test_contingency_type_optional_preserves_abi_values(
963        #[case] value: Option<ContingencyType>,
964        #[case] ffi_value: ContingencyTypeOptional,
965        #[case] discriminant: u8,
966    ) {
967        assert_eq!(ContingencyTypeOptional::from(value), ffi_value);
968        assert_eq!(ffi_value.as_option(), value);
969        assert_eq!(ffi_value as u8, discriminant);
970    }
971
972    #[rstest]
973    #[case(None, TrailingOffsetTypeOptional::NoTrailingOffset, 0)]
974    #[case(Some(TrailingOffsetType::Price), TrailingOffsetTypeOptional::Price, 1)]
975    #[case(
976        Some(TrailingOffsetType::BasisPoints),
977        TrailingOffsetTypeOptional::BasisPoints,
978        2
979    )]
980    #[case(Some(TrailingOffsetType::Ticks), TrailingOffsetTypeOptional::Ticks, 3)]
981    #[case(
982        Some(TrailingOffsetType::PriceTier),
983        TrailingOffsetTypeOptional::PriceTier,
984        4
985    )]
986    fn test_trailing_offset_type_optional_preserves_abi_values(
987        #[case] value: Option<TrailingOffsetType>,
988        #[case] ffi_value: TrailingOffsetTypeOptional,
989        #[case] discriminant: u8,
990    ) {
991        assert_eq!(TrailingOffsetTypeOptional::from(value), ffi_value);
992        assert_eq!(ffi_value.as_option(), value);
993        assert_eq!(ffi_value as u8, discriminant);
994    }
995
996    #[rstest]
997    #[case(None, TriggerTypeOptional::NoTrigger, 0)]
998    #[case(Some(TriggerType::Default), TriggerTypeOptional::Default, 1)]
999    #[case(Some(TriggerType::LastPrice), TriggerTypeOptional::LastPrice, 2)]
1000    #[case(Some(TriggerType::MarkPrice), TriggerTypeOptional::MarkPrice, 3)]
1001    #[case(Some(TriggerType::IndexPrice), TriggerTypeOptional::IndexPrice, 4)]
1002    #[case(Some(TriggerType::BidAsk), TriggerTypeOptional::BidAsk, 5)]
1003    #[case(Some(TriggerType::DoubleLast), TriggerTypeOptional::DoubleLast, 6)]
1004    #[case(Some(TriggerType::DoubleBidAsk), TriggerTypeOptional::DoubleBidAsk, 7)]
1005    #[case(Some(TriggerType::LastOrBidAsk), TriggerTypeOptional::LastOrBidAsk, 8)]
1006    #[case(Some(TriggerType::MidPoint), TriggerTypeOptional::MidPoint, 9)]
1007    fn test_trigger_type_optional_preserves_abi_values(
1008        #[case] value: Option<TriggerType>,
1009        #[case] ffi_value: TriggerTypeOptional,
1010        #[case] discriminant: u8,
1011    ) {
1012        assert_eq!(TriggerTypeOptional::from(value), ffi_value);
1013        assert_eq!(ffi_value.as_option(), value);
1014        assert_eq!(ffi_value as u8, discriminant);
1015    }
1016}