config_it/config/
entity.rs

1use parking_lot::RwLock;
2use serde::de::DeserializeOwned;
3use std::any::{Any, TypeId};
4use std::borrow::Cow;
5use std::sync::atomic::{AtomicU64, Ordering};
6use std::sync::Arc;
7
8use crate::shared::meta::Metadata;
9use crate::shared::ItemID;
10
11/// Number of available words for trivial entity value.
12///
13/// Value `5` makes [`EntityData`] in 32-byte align (96 byte size).
14const TRIVIAL_ENTITY_NUM_WORDS: usize = 5;
15
16///
17/// Config entity type must satisfy this constraint
18///
19pub trait Entity: Send + Sync + Any + 'static {
20    fn as_any(&self) -> &dyn Any;
21    fn as_any_mut(&mut self) -> &mut dyn Any;
22    fn as_serialize(&self) -> &dyn erased_serde::Serialize;
23    fn deserialize(
24        &mut self,
25        de: &mut dyn erased_serde::Deserializer,
26    ) -> Result<(), erased_serde::Error>;
27    fn duplicated(&self) -> Arc<dyn Entity>;
28}
29
30impl<T> Entity for T
31where
32    T: Send + Sync + Any + serde::Serialize + DeserializeOwned + Clone + 'static,
33{
34    fn as_any(&self) -> &dyn Any {
35        self as &dyn Any
36    }
37
38    fn as_any_mut(&mut self) -> &mut dyn Any {
39        self as &mut dyn Any
40    }
41
42    fn deserialize(
43        &mut self,
44        de: &mut dyn erased_serde::Deserializer,
45    ) -> Result<(), erased_serde::Error> {
46        T::deserialize_in_place(de, self)?;
47        Ok(())
48    }
49
50    fn as_serialize(&self) -> &dyn erased_serde::Serialize {
51        self as &dyn erased_serde::Serialize
52    }
53
54    fn duplicated(&self) -> Arc<dyn Entity> {
55        Arc::new(self.clone())
56    }
57}
58
59///
60///
61/// Metadata for configuration entity. This can be used as template for multiple config entity
62///  instances.
63///
64///
65#[derive(Debug)]
66pub struct PropertyInfo {
67    pub(crate) type_id: TypeId,
68    pub(crate) index: usize,
69    pub(crate) metadata: Metadata,
70    pub(crate) vtable: &'static dyn MetadataVTable,
71}
72
73impl PropertyInfo {
74    #[doc(hidden)]
75    pub fn new(
76        type_id: TypeId,
77        index: usize,
78        metadata: Metadata,
79        vtable: &'static dyn MetadataVTable,
80    ) -> Self {
81        Self { type_id, index, metadata, vtable }
82    }
83}
84
85impl std::ops::Deref for PropertyInfo {
86    type Target = Metadata;
87
88    fn deref(&self) -> &Self::Target {
89        &self.metadata
90    }
91}
92
93/// Validation result.
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum Validation {
96    /// Data was valid. No change was made.
97    Valid,
98
99    /// Data was valid. Value was modified to satisfy validator constraint.
100    Modified,
101}
102
103/// Validation result. Error type is plain string to inform user.
104pub type ValidationResult = Result<Validation, std::borrow::Cow<'static, str>>;
105
106/// Signature of function to validate config entity
107pub type ValidateFn<T> = fn(&mut T) -> ValidationResult;
108
109pub trait MetadataVTable: Send + Sync + 'static + std::fmt::Debug {
110    /// Does implement `Copy`?
111    fn implements_copy(&self) -> bool;
112
113    /// Creates default value for this config entity.
114    fn create_default(&self) -> EntityValue;
115
116    /// Create new deserialized entity instance from given deserializer
117    fn deserialize(
118        &self,
119        de: &mut dyn erased_serde::Deserializer,
120    ) -> Result<EntityValue, erased_serde::Error>;
121
122    /// Copy one value from another. Panics when called with unmatched type!
123    fn clone_in_place(&self, src: &dyn Any, dst: &mut dyn Any);
124
125    /// Returns None if validation failed. Some(false) when source value was corrected.
126    ///  Some(true) when value was correct.
127    fn validate(&self, value: &mut dyn Any) -> ValidationResult;
128}
129
130#[derive(cs::Debug)]
131#[doc(hidden)]
132pub struct MetadataVTableImpl<T: 'static> {
133    pub impl_copy: bool,
134    pub fn_default: fn() -> T,
135    pub fn_validate: ValidateFn<T>,
136}
137
138impl<T: Entity + Clone> MetadataVTable for MetadataVTableImpl<T> {
139    fn implements_copy(&self) -> bool {
140        self.impl_copy
141    }
142
143    fn create_default(&self) -> EntityValue {
144        // SAFETY: We know that `vtable.implements_copy()` is strictly managed.
145        unsafe { EntityValue::from_value((self.fn_default)(), self.impl_copy) }
146    }
147
148    fn deserialize(
149        &self,
150        de: &mut dyn erased_serde::Deserializer,
151    ) -> Result<EntityValue, erased_serde::Error> {
152        let mut default = (self.fn_default)();
153        default.deserialize(de)?;
154
155        // SAFETY: We know that `vtable.implements_copy()` is strictly managed.
156        Ok(unsafe { EntityValue::from_value(default, self.impl_copy) })
157    }
158
159    fn clone_in_place(&self, src: &dyn Any, dst: &mut dyn Any) {
160        let src = src.downcast_ref::<T>().unwrap();
161        let dst = dst.downcast_mut::<T>().unwrap();
162
163        dst.clone_from(src);
164    }
165
166    fn validate(&self, value: &mut dyn Any) -> ValidationResult {
167        let value = value.downcast_mut::<T>().unwrap();
168        (self.fn_validate)(value)
169    }
170}
171
172/* ---------------------------------------- Entity Value ---------------------------------------- */
173#[derive(Clone)]
174pub enum EntityValue {
175    Trivial(TrivialEntityValue),
176    Complex(Arc<dyn Entity>),
177}
178
179impl std::fmt::Debug for EntityValue {
180    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181        match self {
182            Self::Trivial(_) => f.debug_struct("Trivial"),
183            Self::Complex(_) => f.debug_struct("Complex"),
184        }
185        .finish()
186    }
187}
188
189type ReinterpretInput<'a> = Result<&'a [usize], &'a mut [usize]>;
190type ReinterpretOutput<'a> = Result<&'a dyn Entity, &'a mut dyn Entity>;
191
192/// Pair of function pointer to retrieve entity trait from given pointer and actual payload.
193#[derive(Clone, Copy)]
194#[doc(hidden)]
195pub struct TrivialEntityValue(
196    for<'a> unsafe fn(ReinterpretInput) -> ReinterpretOutput,
197    [usize; TRIVIAL_ENTITY_NUM_WORDS],
198);
199
200impl Entity for EntityValue {
201    fn as_any(&self) -> &dyn Any {
202        self.as_entity().as_any()
203    }
204
205    fn as_any_mut(&mut self) -> &mut dyn Any {
206        self.as_entity_mut().as_any_mut()
207    }
208
209    fn as_serialize(&self) -> &dyn erased_serde::Serialize {
210        self.as_entity().as_serialize()
211    }
212
213    fn deserialize(
214        &mut self,
215        de: &mut dyn erased_serde::Deserializer,
216    ) -> Result<(), erased_serde::Error> {
217        self.as_entity_mut().deserialize(de)
218    }
219
220    fn duplicated(&self) -> Arc<dyn Entity> {
221        self.as_entity().duplicated()
222    }
223}
224
225impl EntityValue {
226    pub fn as_entity(&self) -> &dyn Entity {
227        match self {
228            EntityValue::Trivial(t) => unsafe { (t.0)(Ok(&t.1)).unwrap_unchecked() },
229            EntityValue::Complex(v) => v.as_ref(),
230        }
231    }
232
233    pub fn as_entity_mut(&mut self) -> &mut dyn Entity {
234        match self {
235            EntityValue::Trivial(t) => unsafe { (t.0)(Err(&mut t.1)).unwrap_err_unchecked() },
236            EntityValue::Complex(v) => {
237                if Arc::strong_count(v) == 1 {
238                    Arc::get_mut(v).unwrap()
239                } else {
240                    *v = v.duplicated();
241                    Arc::get_mut(v).unwrap()
242                }
243            }
244        }
245    }
246
247    pub fn from_trivial<T: Copy + Entity>(value: T) -> Self {
248        // SAFETY: This is safe as long as `T` is trivially copyable.
249        unsafe { Self::from_trivial_unchecked(value) }
250    }
251
252    #[doc(hidden)]
253    pub(crate) unsafe fn from_trivial_unchecked<T: Entity>(value: T) -> Self {
254        if std::mem::size_of::<T>() <= std::mem::size_of::<usize>() * TRIVIAL_ENTITY_NUM_WORDS {
255            let mut buffer = [0usize; TRIVIAL_ENTITY_NUM_WORDS];
256
257            // SAFETY: This is safe as long as `T` is trivially copyable.
258            unsafe {
259                std::ptr::copy_nonoverlapping(&value, buffer.as_mut_ptr() as _, 1);
260            }
261
262            // SAFETY: Won't be used outside of delivered context.
263            unsafe fn retrieve_function<T: Entity>(i: ReinterpretInput) -> ReinterpretOutput {
264                match i {
265                    Ok(x) => Ok(&*(x.as_ptr() as *const T)),
266                    Err(x) => Err(&mut *(x.as_mut_ptr() as *mut T)),
267                }
268            }
269
270            Self::Trivial(TrivialEntityValue(retrieve_function::<T>, buffer))
271        } else {
272            Self::from_complex(value)
273        }
274    }
275
276    pub fn from_complex<T: Entity>(value: T) -> Self {
277        Self::Complex(Arc::new(value))
278    }
279
280    pub(crate) unsafe fn from_value<T: Entity>(value: T, implements_copy: bool) -> Self {
281        if implements_copy {
282            // SAFETY: `implements_copy` must be managed very carefully to make this safe.
283            unsafe { Self::from_trivial_unchecked(value) }
284        } else {
285            Self::from_complex(value)
286        }
287    }
288}
289
290/* ---------------------------------------------------------------------------------------------- */
291/*                                           ENTITY DATA                                          */
292/* ---------------------------------------------------------------------------------------------- */
293
294///
295/// Events are two directional ...
296///
297/// 1. Remote commit entity / Local commit entity
298///     - 'on update' user observer hooked
299///     - 'any value update' observer hooked
300///
301/// 2. Local commit entity silent
302///     - 'any value update' observer hooked
303///
304/// 3. Local set retrieves entity update
305///
306#[derive(cs::Debug)]
307pub struct EntityData {
308    /// Unique entity id for program run-time
309    pub id: ItemID,
310    pub meta: &'static PropertyInfo,
311
312    version: AtomicU64,
313    value: RwLock<EntityValue>,
314
315    #[debug(skip)]
316    hook: Arc<dyn EntityEventHook>,
317}
318
319#[derive(Debug, thiserror::Error)]
320pub enum EntityUpdateError {
321    #[error("Validation failed: {0}")]
322    ValueValidationFailed(Cow<'static, str>),
323
324    #[error("Deserialization failed")]
325    DeserializeFailed(#[from] erased_serde::Error),
326}
327
328impl EntityData {
329    pub(crate) fn new(
330        property_info: &'static PropertyInfo,
331        hook: Arc<dyn EntityEventHook>,
332    ) -> Self {
333        Self {
334            id: ItemID::new_unique_incremental(),
335            version: AtomicU64::new(0),
336            value: RwLock::new(property_info.vtable.create_default()),
337            meta: property_info,
338            hook,
339        }
340    }
341
342    pub(crate) fn version(&self) -> u64 {
343        self.version.load(Ordering::Relaxed)
344    }
345
346    pub(crate) fn property_value(&self) -> (&'static PropertyInfo, EntityValue) {
347        (self.meta, self.value.read().clone())
348    }
349
350    /// Serialize this property into given serializer.
351    pub fn serialize_into<S: serde::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
352        serde::Serialize::serialize(&self.value.read().as_serialize(), ser)
353    }
354
355    /// If `silent` option is disabled, increase config set and source argument's fence
356    ///  by 1, to make self and other instances of config set which shares the same core
357    ///  be aware of this change.
358    pub(crate) fn __apply_value(&self, value: EntityValue) {
359        debug_assert!(self.meta.type_id == value.as_any().type_id());
360
361        *self.value.write() = value;
362        self.version.fetch_add(1, Ordering::Release);
363    }
364
365    /// Attempts to update the central value of a config entity by deserializing the provided input.
366    ///
367    /// This function first deserializes the input to the expected data structure. After successful
368    /// deserialization, it validates the value to ensure it conforms to the expected constraints.
369    /// The method offers three potential outcomes:
370    ///
371    /// 1. Successful deserialization and validation: the value is perfectly valid and requires no
372    ///    alterations.
373    /// 2. Successful deserialization but failed validation: the value needed adjustments to meet
374    ///    the validator's constraints.
375    /// 3. Failed deserialization or validation: an error occurred during the process.
376    ///
377    /// # Returns
378    ///
379    /// * `Ok(true)` - Both deserialization and validation were successful without the need for any
380    ///   modifications.
381    /// * `Ok(false)` - Deserialization succeeded, but the value was adjusted during validation to
382    ///   meet constraints.
383    /// * `Err(_)` - Either the deserialization process or validation failed.
384    ///
385    /// # Type Parameters
386    ///
387    /// * `T`: Represents the type of the deserializer.
388    ///
389    /// # Parameters
390    ///
391    /// * `de`: An instance of the deserializer used to update the central value.
392    pub fn update_value_from<'a, T>(&self, de: T) -> Result<Validation, EntityUpdateError>
393    where
394        T: serde::Deserializer<'a>,
395    {
396        let meta = &self.meta;
397        let vt = &meta.vtable;
398        let mut erased = <dyn erased_serde::Deserializer>::erase(de);
399
400        match vt.deserialize(&mut erased) {
401            Ok(mut built) => {
402                let is_perfect = match vt.validate(built.as_any_mut()) {
403                    Ok(clean) => clean,
404                    Err(e) => return Err(EntityUpdateError::ValueValidationFailed(e)),
405                };
406
407                self.__apply_value(built);
408                Ok(is_perfect)
409            }
410            Err(error) => {
411                tr::debug!(
412                    %error,
413                    name = meta.varname,
414                    r#type = meta.type_name,
415                    "(Deserialization Failed)",
416                );
417                Err(error.into())
418            }
419        }
420    }
421
422    /// Notifies the underlying storage that a field within this group has been updated.
423    ///
424    /// The `touch` method serves as a mechanism to propagate changes to the appropriate parts of
425    /// the system. Depending on the `make_storage_dirty` flag:
426    ///
427    /// - If set to `true`, the notification of change will be broadcasted to all group instances
428    ///   that share the same group context, ensuring synchronization across shared contexts.
429    ///
430    /// - If set to `false`, only the monitor will be notified of the value update, without
431    ///   affecting other group instances.
432    ///
433    /// # Arguments
434    ///
435    /// * `make_storage_dirty`: A boolean flag that determines the scope of the update notification.
436    ///   When set to `true`, it affects all group instances sharing the same context. When `false`,
437    ///   only the monitor is alerted of the change.
438    pub fn touch(&self, make_storage_dirty: bool) {
439        self.hook.on_value_changed(self, !make_storage_dirty);
440    }
441}
442
443pub(crate) trait EntityEventHook: Send + Sync {
444    fn on_value_changed(&self, data: &EntityData, silent: bool);
445}