financial_types/lib.rs
1#![cfg_attr(not(any(feature = "std", test)), no_std)]
2
3//! # Financial Types
4//!
5//! Core financial type definitions for trading systems.
6//!
7//! This crate provides fundamental enums used across financial applications:
8//! - [`UnderlyingAssetType`] — Classification of asset classes (stocks, crypto, forex, etc.)
9//! - [`Action`] — Trading actions (buy, sell)
10//! - [`Side`] — Position directional exposure (long, short)
11//! - [`OptionStyle`] — Option contract style (call, put)
12//!
13//! All enums use `#[repr(u8)]` for compact memory layout and are designed for
14//! high-performance financial systems.
15//!
16//! ## Features
17//!
18//! - Full `serde` serialization/deserialization support
19//! - Optional `utoipa` support for OpenAPI schema generation (enable the `utoipa` feature)
20//! - `#[repr(u8)]` on all enums for deterministic layout
21//! - `#[must_use]` on pure helper methods
22//! - `FromStr`, `TryFrom<&str>`, and `TryFrom<u8>` on every public enum,
23//! returning [`ParseEnumError`] on failure. String parsing is
24//! case-insensitive and trims whitespace.
25//!
26//! ## Wire format
27//!
28//! `serde` JSON encoding is part of the public contract. The string
29//! used for every variant is fixed and SemVer-tracked: renaming any
30//! variant string is a breaking change.
31//!
32//! | Enum | Variant | JSON |
33//! |-----------------------|-------------|---------------|
34//! | `UnderlyingAssetType` | `Crypto` | `"Crypto"` |
35//! | `UnderlyingAssetType` | `Stock` | `"Stock"` |
36//! | `UnderlyingAssetType` | `Forex` | `"Forex"` |
37//! | `UnderlyingAssetType` | `Commodity` | `"Commodity"` |
38//! | `UnderlyingAssetType` | `Bond` | `"Bond"` |
39//! | `UnderlyingAssetType` | `Other` | `"Other"` |
40//! | `UnderlyingAssetType` | `Future` | `"Future"` |
41//! | `UnderlyingAssetType` | `Forward` | `"Forward"` |
42//! | `Action` | `Buy` | `"Buy"` |
43//! | `Action` | `Sell` | `"Sell"` |
44//! | `Action` | `Other` | `"Other"` |
45//! | `Side` | `Long` | `"Long"` |
46//! | `Side` | `Short` | `"Short"` |
47//! | `OptionStyle` | `Call` | `"Call"` |
48//! | `OptionStyle` | `Put` | `"Put"` |
49//!
50//! ## `no_std`
51//!
52//! The crate compiles in `no_std` environments. Disable default features:
53//!
54//! ```toml
55//! [dependencies]
56//! financial_types = { version = "0.1", default-features = false }
57//! ```
58//!
59//! The `alloc` crate is always required (used by `ParseEnumError`).
60//! Re-enable the `std` feature to opt into `std::error::Error`-style
61//! integration that pulls in `serde/std`.
62//!
63//! ## Usage
64//!
65//! ```rust
66//! use financial_types::{Action, Side, OptionStyle, UnderlyingAssetType};
67//!
68//! let action = Action::Buy;
69//! let side = Side::Long;
70//! let style = OptionStyle::Call;
71//! let asset = UnderlyingAssetType::Stock;
72//!
73//! assert_eq!(format!("{action}"), "Buy");
74//! assert_eq!(format!("{side}"), "Long");
75//! assert_eq!(format!("{style}"), "Call");
76//! assert_eq!(format!("{asset}"), "Stock");
77//!
78//! assert!(style.is_call());
79//! assert!(side.is_long());
80//! assert!(action.is_buy());
81//! ```
82
83extern crate alloc;
84
85pub mod prelude;
86
87use alloc::string::{String, ToString};
88use core::fmt;
89use core::str::FromStr;
90use serde::{Deserialize, Serialize};
91
92/// Error returned when a string or `u8` cannot be converted into one of the
93/// public financial enums defined by this crate.
94///
95/// This is the error type produced by `FromStr`, `TryFrom<&str>`, and
96/// `TryFrom<u8>` implementations on [`UnderlyingAssetType`], [`Action`],
97/// [`Side`], and [`OptionStyle`].
98///
99/// # Examples
100///
101/// ```rust
102/// use financial_types::{Side, ParseEnumError};
103/// use std::str::FromStr;
104///
105/// let err = Side::from_str("sideways").unwrap_err();
106/// assert_eq!(err.kind(), "Side");
107/// ```
108#[derive(Debug, Clone, PartialEq, Eq)]
109#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
110pub struct ParseEnumError {
111 /// Name of the enum that failed to parse (e.g. `"Side"`).
112 kind: &'static str,
113 /// Human-readable description of the invalid input.
114 input: String,
115}
116
117impl ParseEnumError {
118 /// Creates a new [`ParseEnumError`].
119 #[must_use]
120 #[inline]
121 pub fn new(kind: &'static str, input: impl Into<String>) -> Self {
122 Self {
123 kind,
124 input: input.into(),
125 }
126 }
127
128 /// Returns the name of the enum that failed to parse.
129 #[must_use]
130 #[inline]
131 pub const fn kind(&self) -> &'static str {
132 self.kind
133 }
134
135 /// Returns the original (stringified) input that was rejected.
136 #[must_use]
137 #[inline]
138 pub fn input(&self) -> &str {
139 &self.input
140 }
141}
142
143impl fmt::Display for ParseEnumError {
144 #[inline]
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 write!(f, "invalid {} value: {:?}", self.kind, self.input)
147 }
148}
149
150impl core::error::Error for ParseEnumError {}
151
152/// Classification of the underlying asset for a financial instrument.
153///
154/// Represents the broad asset class to which an instrument belongs.
155/// Used for routing, risk bucketing, and display purposes.
156///
157/// # Stability
158///
159/// This enum is `#[non_exhaustive]`. New asset classes may be added in
160/// minor releases without a major version bump. Downstream `match`
161/// expressions must include a wildcard arm (`_ =>`).
162///
163/// # Examples
164///
165/// ```rust
166/// use financial_types::UnderlyingAssetType;
167///
168/// let asset = UnderlyingAssetType::default();
169/// assert_eq!(asset, UnderlyingAssetType::Stock);
170/// assert_eq!(format!("{asset}"), "Stock");
171/// ```
172#[derive(
173 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize,
174)]
175#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
176#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
177#[repr(u8)]
178#[non_exhaustive]
179pub enum UnderlyingAssetType {
180 /// Cryptocurrency assets (e.g., BTC, ETH).
181 Crypto = 0,
182 /// Stock/equity assets (e.g., AAPL, GOOGL).
183 #[default]
184 Stock = 1,
185 /// Foreign exchange currency pairs (e.g., EUR/USD).
186 Forex = 2,
187 /// Commodity assets (e.g., Gold, Oil).
188 Commodity = 3,
189 /// Bond/fixed income securities.
190 Bond = 4,
191 /// Other asset types not covered by the above categories.
192 Other = 5,
193 /// Exchange-traded futures contract (e.g., ES, CL, ZB).
194 ///
195 /// Used to mark options whose underlying is a futures price `F`
196 /// rather than a spot price `S` (see Black-76 model).
197 Future = 6,
198 /// OTC / bilateral forward contract on any underlying.
199 ///
200 /// Used to mark options whose underlying is a forward price `F`
201 /// rather than a spot price `S` (see Black-76 model).
202 Forward = 7,
203}
204
205impl UnderlyingAssetType {
206 /// Returns `true` if this is a [`Stock`](Self::Stock) variant.
207 #[must_use]
208 #[inline]
209 pub const fn is_stock(&self) -> bool {
210 matches!(self, Self::Stock)
211 }
212
213 /// Returns `true` if this is a [`Crypto`](Self::Crypto) variant.
214 #[must_use]
215 #[inline]
216 pub const fn is_crypto(&self) -> bool {
217 matches!(self, Self::Crypto)
218 }
219
220 /// Returns `true` if this is a [`Forex`](Self::Forex) variant.
221 #[must_use]
222 #[inline]
223 pub const fn is_forex(&self) -> bool {
224 matches!(self, Self::Forex)
225 }
226
227 /// Returns `true` if this is a [`Commodity`](Self::Commodity) variant.
228 #[must_use]
229 #[inline]
230 pub const fn is_commodity(&self) -> bool {
231 matches!(self, Self::Commodity)
232 }
233
234 /// Returns `true` if this is a [`Bond`](Self::Bond) variant.
235 #[must_use]
236 #[inline]
237 pub const fn is_bond(&self) -> bool {
238 matches!(self, Self::Bond)
239 }
240
241 /// Returns `true` if this is a [`Future`](Self::Future) variant.
242 #[must_use]
243 #[inline]
244 pub const fn is_future(&self) -> bool {
245 matches!(self, Self::Future)
246 }
247
248 /// Returns `true` if this is a [`Forward`](Self::Forward) variant.
249 #[must_use]
250 #[inline]
251 pub const fn is_forward(&self) -> bool {
252 matches!(self, Self::Forward)
253 }
254
255 /// Returns the canonical string representation of this variant.
256 ///
257 /// Matches the [`fmt::Display`] output exactly and is allocation-free.
258 #[must_use]
259 #[inline]
260 pub const fn as_str(&self) -> &'static str {
261 match self {
262 Self::Crypto => "Crypto",
263 Self::Stock => "Stock",
264 Self::Forex => "Forex",
265 Self::Commodity => "Commodity",
266 Self::Bond => "Bond",
267 Self::Other => "Other",
268 Self::Future => "Future",
269 Self::Forward => "Forward",
270 }
271 }
272
273 /// All variants in discriminant order.
274 ///
275 /// Useful for iteration, UI dropdowns, exhaustive validation, and
276 /// schema generation. Order matches the `#[repr(u8)]` values.
277 pub const ALL: &'static [Self] = &[
278 Self::Crypto,
279 Self::Stock,
280 Self::Forex,
281 Self::Commodity,
282 Self::Bond,
283 Self::Other,
284 Self::Future,
285 Self::Forward,
286 ];
287}
288
289impl fmt::Display for UnderlyingAssetType {
290 #[inline]
291 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292 f.write_str(self.as_str())
293 }
294}
295
296impl FromStr for UnderlyingAssetType {
297 type Err = ParseEnumError;
298
299 #[inline]
300 fn from_str(s: &str) -> Result<Self, Self::Err> {
301 match s.trim().to_ascii_lowercase().as_str() {
302 "crypto" => Ok(Self::Crypto),
303 "stock" => Ok(Self::Stock),
304 "forex" => Ok(Self::Forex),
305 "commodity" => Ok(Self::Commodity),
306 "bond" => Ok(Self::Bond),
307 "other" => Ok(Self::Other),
308 "future" => Ok(Self::Future),
309 "forward" => Ok(Self::Forward),
310 _ => Err(ParseEnumError::new("UnderlyingAssetType", s)),
311 }
312 }
313}
314
315impl TryFrom<&str> for UnderlyingAssetType {
316 type Error = ParseEnumError;
317
318 #[inline]
319 fn try_from(value: &str) -> Result<Self, Self::Error> {
320 Self::from_str(value)
321 }
322}
323
324impl TryFrom<u8> for UnderlyingAssetType {
325 type Error = ParseEnumError;
326
327 #[inline]
328 fn try_from(value: u8) -> Result<Self, Self::Error> {
329 match value {
330 0 => Ok(Self::Crypto),
331 1 => Ok(Self::Stock),
332 2 => Ok(Self::Forex),
333 3 => Ok(Self::Commodity),
334 4 => Ok(Self::Bond),
335 5 => Ok(Self::Other),
336 6 => Ok(Self::Future),
337 7 => Ok(Self::Forward),
338 other => Err(ParseEnumError::new(
339 "UnderlyingAssetType",
340 other.to_string(),
341 )),
342 }
343 }
344}
345
346/// Represents trading actions in a financial context.
347///
348/// Defines the fundamental trade operations that can be performed in a
349/// trading system. These actions represent the direction of a trade
350/// transaction.
351///
352/// # Stability
353///
354/// This enum is `#[non_exhaustive]`. New trading actions may be added in
355/// minor releases without a major version bump. Downstream `match`
356/// expressions must include a wildcard arm (`_ =>`).
357///
358/// # Examples
359///
360/// ```rust
361/// use financial_types::Action;
362///
363/// let action = Action::Buy;
364/// assert!(action.is_buy());
365/// assert_eq!(format!("{action}"), "Buy");
366/// ```
367#[derive(
368 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize,
369)]
370#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
371#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
372#[repr(u8)]
373#[non_exhaustive]
374pub enum Action {
375 /// Represents a purchase transaction, where assets are acquired.
376 #[default]
377 Buy = 0,
378 /// Represents a selling transaction, where assets are disposed of.
379 Sell = 1,
380 /// Action is not applicable to this type of transaction.
381 Other = 2,
382}
383
384impl Action {
385 /// Returns `true` if this is a [`Buy`](Self::Buy) action.
386 #[must_use]
387 #[inline]
388 pub const fn is_buy(&self) -> bool {
389 matches!(self, Self::Buy)
390 }
391
392 /// Returns `true` if this is a [`Sell`](Self::Sell) action.
393 #[must_use]
394 #[inline]
395 pub const fn is_sell(&self) -> bool {
396 matches!(self, Self::Sell)
397 }
398
399 /// Returns the canonical string representation of this variant.
400 ///
401 /// Matches the [`fmt::Display`] output exactly and is allocation-free.
402 #[must_use]
403 #[inline]
404 pub const fn as_str(&self) -> &'static str {
405 match self {
406 Self::Buy => "Buy",
407 Self::Sell => "Sell",
408 Self::Other => "Other",
409 }
410 }
411
412 /// All variants in discriminant order.
413 pub const ALL: &'static [Self] = &[Self::Buy, Self::Sell, Self::Other];
414
415 /// Returns the opposite trading action.
416 ///
417 /// - `Buy` → `Sell`
418 /// - `Sell` → `Buy`
419 /// - `Other` → `Other` (no meaningful inverse)
420 #[must_use]
421 #[inline]
422 pub const fn opposite(&self) -> Self {
423 match self {
424 Self::Buy => Self::Sell,
425 Self::Sell => Self::Buy,
426 Self::Other => Self::Other,
427 }
428 }
429}
430
431impl fmt::Display for Action {
432 #[inline]
433 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
434 f.write_str(self.as_str())
435 }
436}
437
438impl FromStr for Action {
439 type Err = ParseEnumError;
440
441 #[inline]
442 fn from_str(s: &str) -> Result<Self, Self::Err> {
443 match s.trim().to_ascii_lowercase().as_str() {
444 "buy" => Ok(Self::Buy),
445 "sell" => Ok(Self::Sell),
446 "other" => Ok(Self::Other),
447 _ => Err(ParseEnumError::new("Action", s)),
448 }
449 }
450}
451
452impl TryFrom<&str> for Action {
453 type Error = ParseEnumError;
454
455 #[inline]
456 fn try_from(value: &str) -> Result<Self, Self::Error> {
457 Self::from_str(value)
458 }
459}
460
461impl TryFrom<u8> for Action {
462 type Error = ParseEnumError;
463
464 #[inline]
465 fn try_from(value: u8) -> Result<Self, Self::Error> {
466 match value {
467 0 => Ok(Self::Buy),
468 1 => Ok(Self::Sell),
469 2 => Ok(Self::Other),
470 other => Err(ParseEnumError::new("Action", other.to_string())),
471 }
472 }
473}
474
475/// Defines the directional exposure of a financial position.
476///
477/// Indicates whether a trader expects to profit from rising prices (Long)
478/// or falling prices (Short). This is a fundamental concept in trading that
479/// determines how profits and losses are calculated and affects risk
480/// management considerations.
481///
482/// # Stability
483///
484/// This enum is intentionally **exhaustive**. Position directionality is
485/// a closed two-state concept (long vs. short); no future variants are
486/// planned. Downstream code may rely on exhaustive `match`.
487///
488/// # Examples
489///
490/// ```rust
491/// use financial_types::Side;
492///
493/// let side = Side::Long;
494/// assert!(side.is_long());
495/// assert!(!side.is_short());
496/// assert_eq!(format!("{side}"), "Long");
497/// ```
498#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
499#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
500#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
501#[repr(u8)]
502pub enum Side {
503 /// Profits when the underlying asset's price increases.
504 /// Long positions involve buying an asset with the expectation of selling
505 /// at a higher price.
506 #[default]
507 Long = 0,
508 /// Profits when the underlying asset's price decreases.
509 /// Short positions involve selling an asset (often borrowed) with the
510 /// expectation of buying it back at a lower price.
511 Short = 1,
512}
513
514impl Side {
515 /// Returns `true` if this is a [`Long`](Self::Long) position.
516 #[must_use]
517 #[inline]
518 pub const fn is_long(&self) -> bool {
519 matches!(self, Self::Long)
520 }
521
522 /// Returns `true` if this is a [`Short`](Self::Short) position.
523 #[must_use]
524 #[inline]
525 pub const fn is_short(&self) -> bool {
526 matches!(self, Self::Short)
527 }
528
529 /// Returns the opposite side.
530 ///
531 /// - `Long` → `Short`
532 /// - `Short` → `Long`
533 #[must_use]
534 #[inline]
535 pub const fn opposite(&self) -> Self {
536 match self {
537 Self::Long => Self::Short,
538 Self::Short => Self::Long,
539 }
540 }
541
542 /// Returns the canonical string representation of this variant.
543 ///
544 /// Matches the [`fmt::Display`] output exactly and is allocation-free.
545 #[must_use]
546 #[inline]
547 pub const fn as_str(&self) -> &'static str {
548 match self {
549 Self::Long => "Long",
550 Self::Short => "Short",
551 }
552 }
553
554 /// All variants in discriminant order.
555 pub const ALL: &'static [Self] = &[Self::Long, Self::Short];
556}
557
558impl fmt::Display for Side {
559 #[inline]
560 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
561 f.write_str(self.as_str())
562 }
563}
564
565impl fmt::Debug for Side {
566 #[inline]
567 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
568 match self {
569 Self::Long => write!(f, "Side::Long"),
570 Self::Short => write!(f, "Side::Short"),
571 }
572 }
573}
574
575impl FromStr for Side {
576 type Err = ParseEnumError;
577
578 #[inline]
579 fn from_str(s: &str) -> Result<Self, Self::Err> {
580 match s.trim().to_ascii_lowercase().as_str() {
581 "long" => Ok(Self::Long),
582 "short" => Ok(Self::Short),
583 _ => Err(ParseEnumError::new("Side", s)),
584 }
585 }
586}
587
588impl TryFrom<&str> for Side {
589 type Error = ParseEnumError;
590
591 #[inline]
592 fn try_from(value: &str) -> Result<Self, Self::Error> {
593 Self::from_str(value)
594 }
595}
596
597impl TryFrom<u8> for Side {
598 type Error = ParseEnumError;
599
600 #[inline]
601 fn try_from(value: u8) -> Result<Self, Self::Error> {
602 match value {
603 0 => Ok(Self::Long),
604 1 => Ok(Self::Short),
605 other => Err(ParseEnumError::new("Side", other.to_string())),
606 }
607 }
608}
609
610/// Specifies the style of an option contract.
611///
612/// Defines the fundamental classification of options contracts based on their
613/// payoff direction. The style determines whether the holder has the right to
614/// buy (Call) or sell (Put) the underlying asset.
615///
616/// This is a critical attribute for options contracts as it directly affects
617/// valuation, pricing models, and exercise strategies.
618///
619/// # Stability
620///
621/// This enum is intentionally **exhaustive**. Option payoff direction is
622/// a closed two-state concept (call vs. put); no future variants are
623/// planned. Downstream code may rely on exhaustive `match`.
624///
625/// # Examples
626///
627/// ```rust
628/// use financial_types::OptionStyle;
629///
630/// let style = OptionStyle::Call;
631/// assert!(style.is_call());
632/// assert!(!style.is_put());
633/// assert_eq!(format!("{style}"), "Call");
634/// assert!(OptionStyle::Call < OptionStyle::Put);
635/// ```
636#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
637#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
638#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
639#[repr(u8)]
640pub enum OptionStyle {
641 /// A call option gives the holder the right (but not obligation) to **buy**
642 /// the underlying asset at the strike price before or at expiration.
643 /// Call options typically increase in value when the underlying asset price rises.
644 #[default]
645 Call = 0,
646 /// A put option gives the holder the right (but not obligation) to **sell**
647 /// the underlying asset at the strike price before or at expiration.
648 /// Put options typically increase in value when the underlying asset price falls.
649 Put = 1,
650}
651
652impl OptionStyle {
653 /// Returns `true` if this is a [`Call`](Self::Call) option.
654 #[must_use]
655 #[inline]
656 pub const fn is_call(&self) -> bool {
657 matches!(self, Self::Call)
658 }
659
660 /// Returns `true` if this is a [`Put`](Self::Put) option.
661 #[must_use]
662 #[inline]
663 pub const fn is_put(&self) -> bool {
664 matches!(self, Self::Put)
665 }
666
667 /// Returns the opposite option style.
668 ///
669 /// - `Call` → `Put`
670 /// - `Put` → `Call`
671 #[must_use]
672 #[inline]
673 pub const fn opposite(&self) -> Self {
674 match self {
675 Self::Call => Self::Put,
676 Self::Put => Self::Call,
677 }
678 }
679
680 /// Returns the canonical string representation of this variant.
681 ///
682 /// Matches the [`fmt::Display`] output exactly and is allocation-free.
683 #[must_use]
684 #[inline]
685 pub const fn as_str(&self) -> &'static str {
686 match self {
687 Self::Call => "Call",
688 Self::Put => "Put",
689 }
690 }
691
692 /// All variants in discriminant order.
693 pub const ALL: &'static [Self] = &[Self::Call, Self::Put];
694}
695
696impl fmt::Display for OptionStyle {
697 #[inline]
698 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
699 f.write_str(self.as_str())
700 }
701}
702
703impl fmt::Debug for OptionStyle {
704 #[inline]
705 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
706 match self {
707 Self::Call => write!(f, "OptionStyle::Call"),
708 Self::Put => write!(f, "OptionStyle::Put"),
709 }
710 }
711}
712
713impl FromStr for OptionStyle {
714 type Err = ParseEnumError;
715
716 #[inline]
717 fn from_str(s: &str) -> Result<Self, Self::Err> {
718 match s.trim().to_ascii_lowercase().as_str() {
719 "call" => Ok(Self::Call),
720 "put" => Ok(Self::Put),
721 _ => Err(ParseEnumError::new("OptionStyle", s)),
722 }
723 }
724}
725
726impl TryFrom<&str> for OptionStyle {
727 type Error = ParseEnumError;
728
729 #[inline]
730 fn try_from(value: &str) -> Result<Self, Self::Error> {
731 Self::from_str(value)
732 }
733}
734
735impl TryFrom<u8> for OptionStyle {
736 type Error = ParseEnumError;
737
738 #[inline]
739 fn try_from(value: u8) -> Result<Self, Self::Error> {
740 match value {
741 0 => Ok(Self::Call),
742 1 => Ok(Self::Put),
743 other => Err(ParseEnumError::new("OptionStyle", other.to_string())),
744 }
745 }
746}
747
748#[cfg(feature = "proptest")]
749mod proptest_support {
750 use super::{Action, OptionStyle, Side, UnderlyingAssetType};
751 use proptest::prelude::*;
752
753 impl Arbitrary for UnderlyingAssetType {
754 type Parameters = ();
755 type Strategy = BoxedStrategy<Self>;
756
757 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
758 prop_oneof![
759 Just(Self::Crypto),
760 Just(Self::Stock),
761 Just(Self::Forex),
762 Just(Self::Commodity),
763 Just(Self::Bond),
764 Just(Self::Other),
765 Just(Self::Future),
766 Just(Self::Forward),
767 ]
768 .boxed()
769 }
770 }
771
772 impl Arbitrary for Action {
773 type Parameters = ();
774 type Strategy = BoxedStrategy<Self>;
775
776 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
777 prop_oneof![Just(Self::Buy), Just(Self::Sell), Just(Self::Other)].boxed()
778 }
779 }
780
781 impl Arbitrary for Side {
782 type Parameters = ();
783 type Strategy = BoxedStrategy<Self>;
784
785 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
786 prop_oneof![Just(Self::Long), Just(Self::Short)].boxed()
787 }
788 }
789
790 impl Arbitrary for OptionStyle {
791 type Parameters = ();
792 type Strategy = BoxedStrategy<Self>;
793
794 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
795 prop_oneof![Just(Self::Call), Just(Self::Put)].boxed()
796 }
797 }
798}