Skip to main content

ankurah_core/property/value/
lww.rs

1use std::{marker::PhantomData, sync::Arc};
2
3use crate::{
4    entity::Entity,
5    property::{
6        backend::{LWWBackend, PropertyBackend},
7        traits::{FromActiveType, FromEntity, PropertyError},
8        InitializeWith, Property, PropertyName, Value,
9    },
10};
11
12use ankurah_signals::{
13    signal::{Listener, ListenerGuard},
14    Signal,
15};
16
17#[derive(Clone)]
18pub struct LWW<T: Property> {
19    pub property_name: PropertyName,
20    pub backend: Arc<LWWBackend>,
21    pub entity: Entity,
22    phantom: PhantomData<T>,
23}
24
25impl<T: Property> std::fmt::Debug for LWW<T> {
26    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27        f.debug_struct("LWW").field("property_name", &self.property_name).finish()
28    }
29}
30
31impl<T: Property> LWW<T> {
32    pub fn set(&self, value: &T) -> Result<(), PropertyError> {
33        if !self.entity.is_writable() {
34            return Err(PropertyError::TransactionClosed);
35        }
36        let value = value.into_value()?;
37        self.backend.set(self.property_name.clone(), value);
38        Ok(())
39    }
40
41    pub fn get(&self) -> Result<T, PropertyError> {
42        let value = self.get_value();
43        T::from_value(value)
44    }
45
46    pub fn get_value(&self) -> Option<Value> { self.backend.get(&self.property_name) }
47}
48
49impl<T: Property> FromEntity for LWW<T> {
50    fn from_entity(property_name: PropertyName, entity: &Entity) -> Self {
51        let backend = entity.get_backend::<LWWBackend>().expect("LWW Backend should exist");
52        Self { property_name, backend, entity: entity.clone(), phantom: PhantomData }
53    }
54}
55
56impl<T: Property> FromActiveType<LWW<T>> for T {
57    fn from_active(active: LWW<T>) -> Result<Self, PropertyError>
58    where Self: Sized {
59        active.get()
60    }
61}
62
63impl<T: Property> InitializeWith<T> for LWW<T> {
64    fn initialize_with(entity: &Entity, property_name: PropertyName, value: &T) -> Self {
65        let new = Self::from_entity(property_name, entity);
66        new.set(value).unwrap();
67        new
68    }
69}
70
71impl<T: Property> ankurah_signals::Signal for LWW<T> {
72    fn listen(&self, listener: Listener) -> ListenerGuard { self.backend.listen_field(&self.property_name, listener) }
73
74    fn broadcast_id(&self) -> ankurah_signals::broadcast::BroadcastId { self.backend.field_broadcast_id(&self.property_name) }
75}
76
77impl<T: Property> ankurah_signals::Subscribe<T> for LWW<T>
78where T: Clone + Send + Sync + 'static
79{
80    fn subscribe<F>(&self, listener: F) -> ankurah_signals::SubscriptionGuard
81    where F: ankurah_signals::subscribe::IntoSubscribeListener<T> {
82        let listener = listener.into_subscribe_listener();
83        let lww = self.clone();
84        let subscription = self.listen(Arc::new(move |_| {
85            // Get current value when the broadcast fires
86            if let Ok(current_value) = lww.get() {
87                listener(current_value);
88            }
89        }));
90        ankurah_signals::SubscriptionGuard::new(subscription)
91    }
92}
93
94#[cfg(any(feature = "wasm", feature = "uniffi"))]
95pub mod ffi {
96    //! FFI wrapper types for LWW backend (WASM and UniFFI)
97    use super::*;
98    use crate::property::Json;
99    #[cfg(feature = "wasm")]
100    use ::wasm_bindgen::prelude::*;
101    use ankurah_derive::impl_provided_wrapper_types;
102    impl_provided_wrapper_types!("src/property/value/lww.ron");
103}
104#[cfg(any(feature = "wasm", feature = "uniffi"))]
105pub use ffi::*;