Skip to main content

minarrow/traits/
custom_value.rs

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