minarrow/traits/
custom_value.rs

1//! # **Custom Value Trait Module** - *Makes all your Any+Send+Sync types automatically compatible with Minarrow*
2//! 
3//! Includes the [`CustomValue`] trait, enabling storage of arbitrary user-defined
4//! types inside [`enums::Value::Custom`] while maintaining a unified interface
5//! with scalars, arrays, and tables.
6//!
7//! This mechanism supports advanced or intermediate pipeline states—such as
8//! partial aggregates, sketches, or engine-specific outputs—that do not fit into
9//! the standard Arrow type system.
10//!
11//! Dynamic dispatch and `Any` downcasting allow recovery of the concrete type
12//! at runtime for type-specific operations. The library provides a blanket
13//! implementation so that any `Send + Sync + Clone + PartialEq + Debug + 'static`
14//! type can be used without manual implementation.
15//!
16//! ## Key Points
17//! - Enables integration of custom, non-Arrow types in Minarrow pipelines.
18//! - Supports deep cloning, semantic equality, and safe downcasting.
19//! - Borrowed types are not supported; use owned types or `Arc`.
20//! - Intended for specialised use cases; most data should use Arrow-compatible arrays.
21
22use std::{any::Any, sync::Arc};
23
24/// # Custom Value
25/// 
26/// Trait for any object that can be stored in `enums::Value::Custom`.
27///
28/// `CustomValue` extends *MinArrow's* `Value` universe, allowing engines or 
29/// analytics to handle intermediate states and custom types 
30/// within the same pipeline abstraction as scalars, arrays, and tables.
31///
32/// You must then manage downcasting on top of the base enum match, so it 
33/// it's not the most ergonomic situation, but is available.
34/// 
35/// Typical use cases include:
36/// - Accumulators, partial aggregates, or sketches.
37/// - Custom algorithm outputs.
38/// - Arbitrary user-defined types requiring unified pipeline integration.
39///
40/// **Dynamic dispatch and downcasting** are used at runtime to recover the inner type 
41/// and perform type-specific logic, such as merging, reduction, or finalisation.
42///
43/// ### Implementation Notes:
44/// - **Manual implementation is not required**.  
45/// - Any type that implements `Debug`, `Clone`, `PartialEq`, and is `Send + Sync + 'static` 
46///   automatically satisfies `CustomValue` via the blanket impl.
47/// - `Any` is automatically implemented by Rust for all `'static` types.  
48///
49/// ### Borrowing Constraints:
50/// - **Borrowed types cannot be used in `Value::Custom` directly**, since `Any` requires `'static`.  
51/// - To store borrowed data, first promote it to an owned type or wrap it in `Arc`.
52pub trait CustomValue: Any + Send + Sync + std::fmt::Debug {
53    
54    /// Downcasts the type as `Any`
55    fn as_any(&self) -> &dyn Any;
56    /// Returns a deep clone of the object.
57    /// 
58    /// Additionally, the `Value` enum automatically derives `Clone`, which is a 
59    /// shallow `Arc` clone by default.
60    fn deep_clone(&self) -> Arc<dyn CustomValue>;
61
62    /// Performs semantic equality on the boxed object.
63    ///
64    /// This enables `PartialEq` to be implemented for `Value`,
65    /// since `dyn CustomValue` cannot use `==` directly.
66    fn eq_box(&self, other: &dyn CustomValue) -> bool;
67}
68
69/// Provided extension types implement `Clone`, `PartialEq`, `Debug`
70/// and is `Send` + `Sync + Any`, these methods implement automatically.
71impl<T> CustomValue for T
72where
73    T: Any + Send + Sync + Clone + PartialEq + std::fmt::Debug,
74{
75    fn as_any(&self) -> &dyn Any {
76        self
77    }
78
79    fn deep_clone(&self) -> Arc<dyn CustomValue> {
80        Arc::new(self.clone())
81    }
82
83    fn eq_box(&self, other: &dyn CustomValue) -> bool {
84        other.as_any().downcast_ref::<T>().map_or(false, |o| self == o)
85    }
86}