tvdata_rs/scanner/
metainfo.rs1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5pub struct ScannerMetainfo {
6 #[serde(default)]
7 pub financial_currency: Option<String>,
8 #[serde(default)]
9 pub fields: Vec<ScannerFieldMetainfo>,
10}
11
12impl ScannerMetainfo {
13 pub fn field(&self, name: &str) -> Option<&ScannerFieldMetainfo> {
14 self.fields.iter().find(|field| field.name == name)
15 }
16
17 pub fn supports_field(&self, name: &str) -> bool {
18 self.field(name).is_some()
19 }
20
21 pub fn fields_by_type<'a>(
22 &'a self,
23 field_type: &'a str,
24 ) -> impl Iterator<Item = &'a ScannerFieldMetainfo> + 'a {
25 self.fields
26 .iter()
27 .filter(move |field| field.field_type.as_str() == field_type)
28 }
29}
30
31#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
32pub struct ScannerFieldMetainfo {
33 #[serde(rename = "n")]
34 pub name: String,
35 #[serde(rename = "t")]
36 pub field_type: ScannerFieldType,
37 #[serde(rename = "r", default)]
38 pub range: Option<Value>,
39}
40
41impl ScannerFieldMetainfo {
42 pub fn enum_values(&self) -> Option<&[Value]> {
43 self.range.as_ref()?.as_array().map(Vec::as_slice)
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
48#[serde(transparent)]
49pub struct ScannerFieldType(String);
50
51impl ScannerFieldType {
52 pub fn as_str(&self) -> &str {
53 &self.0
54 }
55
56 pub fn is_numeric_like(&self) -> bool {
57 matches!(
58 self.as_str(),
59 "number" | "percent" | "price" | "fundamental_price" | "num_slice"
60 )
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use serde_json::json;
67
68 use super::*;
69
70 #[test]
71 fn metainfo_looks_up_fields_and_types() {
72 let metainfo = ScannerMetainfo {
73 financial_currency: Some("USD".to_owned()),
74 fields: vec![
75 ScannerFieldMetainfo {
76 name: "close".to_owned(),
77 field_type: ScannerFieldType("price".to_owned()),
78 range: None,
79 },
80 ScannerFieldMetainfo {
81 name: "country".to_owned(),
82 field_type: ScannerFieldType("text".to_owned()),
83 range: Some(json!(["United States", "Canada"])),
84 },
85 ],
86 };
87
88 assert!(metainfo.supports_field("close"));
89 assert_eq!(
90 metainfo
91 .field("country")
92 .and_then(ScannerFieldMetainfo::enum_values),
93 Some(&[json!("United States"), json!("Canada")][..]),
94 );
95 assert_eq!(metainfo.fields_by_type("price").count(), 1);
96 assert!(
97 metainfo
98 .field("close")
99 .is_some_and(|field| field.field_type.is_numeric_like())
100 );
101 }
102}