egui_charts/data/
options_volume.rs1use chrono::NaiveDate;
4use std::ops::RangeInclusive;
5use std::sync::{Arc, Mutex, PoisonError, Weak};
6
7#[derive(Clone, Debug, PartialEq, Eq)]
9pub struct OptionsVolumeQuery {
10 pub symbol: String,
12 pub expiries: RangeInclusive<NaiveDate>,
14}
15
16#[derive(Clone, Copy, Debug, PartialEq)]
19pub struct OptionsVolume {
20 pub strike: f64,
22 pub calls: f64,
24 pub puts: f64,
26}
27
28pub(super) struct Snapshot<T> {
29 values: Mutex<T>,
30 wake: Box<dyn Fn() + Send + Sync>,
31}
32
33impl<T> Snapshot<T> {
34 pub(super) fn new(values: T, wake: impl Fn() + Send + Sync + 'static) -> Arc<Self> {
35 Arc::new(Self {
36 values: Mutex::new(values),
37 wake: Box::new(wake),
38 })
39 }
40
41 pub(super) fn read<R>(&self, read: impl FnOnce(&T) -> R) -> R {
42 read(&self.values.lock().unwrap_or_else(PoisonError::into_inner))
43 }
44
45 pub(super) fn update<R>(&self, update: impl FnOnce(&mut T) -> Option<R>) -> Option<R> {
46 let result = update(&mut self.values.lock().unwrap_or_else(PoisonError::into_inner));
47 if result.is_some() {
48 (self.wake)();
49 }
50 result
51 }
52}
53
54#[derive(Clone)]
57pub struct OptionsVolumeSink(Weak<Snapshot<Arc<[OptionsVolume]>>>);
58
59impl OptionsVolumeSink {
60 pub fn push(&self, values: Vec<OptionsVolume>) {
63 if let Some(snapshot) = self.0.upgrade() {
64 snapshot.update(|latest| {
65 *latest = values.into();
66 Some(())
67 });
68 }
69 }
70
71 pub fn is_active(&self) -> bool {
73 self.0.strong_count() > 0
74 }
75}
76
77#[cfg(feature = "studies")]
78#[derive(Clone)]
79pub(crate) struct OptionsVolumeSource(Arc<Snapshot<Arc<[OptionsVolume]>>>);
80
81#[cfg(feature = "studies")]
82impl OptionsVolumeSource {
83 pub(crate) fn new(wake: impl Fn() + Send + Sync + 'static) -> (Self, OptionsVolumeSink) {
84 let snapshot = Snapshot::new(Arc::from([]), wake);
85 let sink = OptionsVolumeSink(Arc::downgrade(&snapshot));
86 (Self(snapshot), sink)
87 }
88
89 pub(crate) fn values(&self) -> Arc<[OptionsVolume]> {
90 self.0.read(Arc::clone)
91 }
92}