trading-charts 0.1.2

Rust binding of Lightweight Charts for Leptos
use super::{js::TradingChart as JsChart, JsError};
use crate::data::{series::Series, options::ChartOptions, Candlestick, Marker};
use serde_wasm_bindgen::to_value;
use serde::Serialize;
use wasm_bindgen::JsValue;
use web_sys::HtmlDivElement;
use std::sync::{
    atomic::{AtomicBool, Ordering},
    Arc,
    Mutex,
};

#[derive(Clone)]
pub struct TradingChartBinding {
    options: Arc<JsValue>,
    chart:   Arc<Mutex<JsChart>>,
    bound:   Arc<AtomicBool>,
}

impl TradingChartBinding {
    pub(crate) fn new(options: Option<&ChartOptions>) -> Result<Self, JsError> {
        let options = Arc::new(match options.map(to_value) {
            None => JsValue::NULL,
            Some(Ok(options)) => options,
            Some(Err(err)) => {
                return Err(JsError::from(err));
            }
        });

        Ok(Self {
            options,
            chart: Arc::new(Mutex::new(JsChart::new())),
            bound: Arc::new(AtomicBool::new(false)),
        })
    }

    pub(crate) fn apply_chart_options(&self, options: &ChartOptions) -> Result<(), JsError> {
        if !self.bound.load(Ordering::SeqCst) {
            return Ok(());
        }

        self.chart.lock().unwrap().applyCharOptions(to_value(options)?)?;

        Ok(())
    }

    pub(crate) fn bind_chart(&self, node: HtmlDivElement) -> Result<(), JsError> {
        let chart = self.chart.lock().unwrap();
        let options = self.options.as_ref();

        self.bound.store(true, Ordering::SeqCst);
        Ok(chart.bindChart(node, options.clone())?)
    }

    pub(crate) fn add_series<Dat, Opt>(&self, series: &mut Series<Dat, Opt>) -> Result<(), JsError>
    where
        Dat: Serialize + Clone,
        Opt: Serialize + Clone, {
        let chart = self.chart.lock().unwrap();
        let id = chart.addSeries(series.to_value()?)?;

        series.set_id(id);
        Ok(())
    }

    #[allow(dead_code)]
    pub(crate) fn update_series_options(&self, series_id: String, options: &impl Serialize) -> Result<(), JsError> {
        let chart = self.chart.lock().unwrap();

        Ok(chart.updateSeriesOptions(series_id, to_value(options)?)?)
    }

    #[allow(dead_code)]
    pub(crate) fn update_data(&self, series_id: String, data: &Vec<Candlestick>) -> Result<(), JsError> {
        let chart = self.chart.lock().unwrap();

        Ok(chart.updateData(series_id, to_value(data)?)?)
    }

    #[allow(dead_code)]
    pub(crate) fn set_marker(&self, series_id: String, marker: &Marker) -> Result<(), JsError> {
        let chart = self.chart.lock().unwrap();

        Ok(chart.setMarker(series_id, to_value(marker)?)?)
    }

    #[allow(dead_code)]
    pub(crate) fn set_markers(&self, series_id: String, markers: &Vec<Marker>) -> Result<(), JsError> {
        let chart = self.chart.lock().unwrap();

        Ok(chart.setMarkers(series_id, to_value(markers)?)?)
    }
}

impl Drop for TradingChartBinding {
    fn drop(&mut self) {
        self.chart.lock().unwrap().destroy();
    }
}

unsafe impl Send for TradingChartBinding {}
unsafe impl Sync for TradingChartBinding {}