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}