Skip to main content

finance_query/models/
format.rs

1//! Compile-time format type parameters for `FormattedValue`-bearing structs.
2//!
3//! Structs like [`Quote`](crate::Quote) carry a format type parameter `F: Format`
4//! that controls what type each numeric field holds:
5//!
6//! | `F`      | `F::Value<f64>`         | Access pattern            |
7//! |----------|-------------------------|---------------------------|
8//! | [`Both`] | `FormattedValue<f64>`   | `.raw` / `.fmt` / `.long_fmt` |
9//! | [`Raw`]  | `f64`                   | direct — no unwrapping (**default**) |
10//! | [`Pretty`] | `String`              | human-readable string     |
11//!
12//! # Quick start
13//!
14//! ```no_run
15//! use finance_query::{Ticker, format};
16//!
17//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
18//! // quote() returns Quote<Raw> by default — fields are plain f64/i64
19//! let quote: finance_query::Quote<format::Raw> = Ticker::new("AAPL").await?.quote().await?;
20//! let price: Option<f64> = quote.regular_market_price;
21//! # Ok(())
22//! # }
23//! ```
24
25use crate::models::quote::FormattedValue;
26
27mod sealed {
28    pub trait Sealed {}
29}
30
31/// Marker trait that controls how [`FormattedValue`](crate::FormattedValue) fields are typed.
32///
33/// Sealed — only [`Both`], [`Raw`], and [`Pretty`] implement this trait.
34pub trait Format: sealed::Sealed + Clone + std::fmt::Debug + PartialEq + 'static {
35    /// The concrete field type for a numeric value of type `T`.
36    type Value<T: Clone + std::fmt::Debug + PartialEq + serde::Serialize + for<'de> serde::Deserialize<'de>>: Clone
37        + std::fmt::Debug
38        + PartialEq
39        + serde::Serialize
40        + for<'de> serde::Deserialize<'de>;
41
42    /// Extract the raw numeric value from a `Value<T>`, if available.
43    ///
44    /// Returns `Some(T)` for [`Both`] (from `.raw`) and [`Raw`] (the value itself),
45    /// `None` for [`Pretty`] (no numeric representation is stored).
46    fn raw_from<
47        T: Clone + std::fmt::Debug + PartialEq + serde::Serialize + for<'de> serde::Deserialize<'de>,
48    >(
49        value: &Self::Value<T>,
50    ) -> Option<T>;
51}
52
53/// Full format — fields hold `FormattedValue<T>` with `raw`, `fmt`, and `long_fmt`.
54///
55/// Obtain via [`Quote::into_formatted`](crate::Quote::into_formatted).
56/// This is the form that can be deserialized directly from Yahoo Finance JSON.
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
58pub struct Both;
59
60/// Raw format — fields hold `T` directly (e.g. `f64`, `i64`). **This is the default.**
61///
62/// Obtain via [`Ticker::quote()`](crate::Ticker::quote) (the default return type),
63/// [`Quote::into_raw`](crate::Quote::into_raw), or
64/// [`Quote::as_raw`](crate::Quote::as_raw). No `Option`-wrapping of the value itself;
65/// the `Option` at the field level reflects missing data from the API.
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub struct Raw;
68
69/// Pretty format — fields hold an `Option<String>` with the human-readable representation.
70///
71/// Obtain via [`Quote::into_pretty`](crate::Quote::into_pretty).
72/// Falls back to `long_fmt` when `fmt` is absent.
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
74pub struct Pretty;
75
76impl sealed::Sealed for Both {}
77impl sealed::Sealed for Raw {}
78impl sealed::Sealed for Pretty {}
79
80impl Format for Both {
81    type Value<
82        T: Clone + std::fmt::Debug + PartialEq + serde::Serialize + for<'de> serde::Deserialize<'de>,
83    > = FormattedValue<T>;
84
85    fn raw_from<
86        T: Clone + std::fmt::Debug + PartialEq + serde::Serialize + for<'de> serde::Deserialize<'de>,
87    >(
88        value: &FormattedValue<T>,
89    ) -> Option<T> {
90        value.raw.clone()
91    }
92}
93
94impl Format for Raw {
95    type Value<
96        T: Clone + std::fmt::Debug + PartialEq + serde::Serialize + for<'de> serde::Deserialize<'de>,
97    > = T;
98
99    fn raw_from<
100        T: Clone + std::fmt::Debug + PartialEq + serde::Serialize + for<'de> serde::Deserialize<'de>,
101    >(
102        value: &T,
103    ) -> Option<T> {
104        Some(value.clone())
105    }
106}
107
108impl Format for Pretty {
109    type Value<
110        T: Clone + std::fmt::Debug + PartialEq + serde::Serialize + for<'de> serde::Deserialize<'de>,
111    > = String;
112
113    fn raw_from<
114        T: Clone + std::fmt::Debug + PartialEq + serde::Serialize + for<'de> serde::Deserialize<'de>,
115    >(
116        _value: &String,
117    ) -> Option<T> {
118        None
119    }
120}