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}