scovich commented on code in PR #9295:
URL: https://github.com/apache/arrow-rs/pull/9295#discussion_r2747831173
##########
arrow-array/src/array/mod.rs:
##########
@@ -500,6 +574,76 @@ unsafe impl<T: Array> Array for &T {
}
}
+/// Returns the innermost `ArrayRef` from potentially nested `Arc<dyn Array>`
wrappers.
+fn innermost_array_ref(array: Cow<'_, ArrayRef>) -> ArrayRef {
+ // Peel away the Cow and the Arc, then recurse on the referent.
+ (**array)
+ .as_array_ref_opt()
+ .unwrap_or_else(|| array.into_owned())
+}
+
+/// Downcasts an [`ArrayRef`] to `Arc<T>`, or returns the original on type
mismatch.
+///
+/// This provides zero-cost downcasting when the dynamic type matches,
avoiding cloning
+/// through [`ArrayData`]. Automatically handles nested `Arc<dyn Array>`
wrappers.
+///
+/// If the Arc contains nested `Arc<dyn Array>`, this method unwraps the
innermost Arc.
+///
+/// ```
+/// # use std::sync::Arc;
+/// # use arrow_array::{Array, ArrayRef, Int32Array, StringArray};
+/// # use arrow_array::downcast_array_ref;
+/// let array: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3]));
+///
+/// let typed: Arc<Int32Array> = downcast_array_ref(array.clone()).unwrap();
+/// assert_eq!(typed.len(), 3);
+///
+/// assert!(downcast_array_ref::<StringArray>(array).is_err());
+/// ```
+pub fn downcast_array_ref<T: Array + 'static>(array: ArrayRef) ->
Result<Arc<T>, ArrayRef> {
+ // SAFETY STRATEGY:
+ //
+ // This function performs two checks to ensure it's safe to reinterpret
+ // Arc<dyn Array> as Arc<T>:
+ //
+ // 1. Type verification via Any::downcast_ref ensures the dynamic type is T
+ // 2. Pointer provenance check ensures the Arc was formed by unsized
coercion
+ // from Arc<T>, not through a wrapper like Arc<&dyn Array> or
Arc<Box<dyn Array>>
+ //
+ // NOTE: The second check is unsound if `Array::as_any()` returns a
reference to any field of
+ // (any sub-object of) `self`. All canonical array types either return
&self or dereference an
+ // internal ArrayRef, both of which satisfy the safety requirements of
`Arc::from_raw`.
+ //
+ // Only if both checks pass do we reconstruct Arc<T> from the same pointer
+ // that Arc::into_raw gave us, which is safe because:
+ // - Type correctness is guaranteed by check #1
+ // - Same allocation/pointer is guaranteed by check #2
+ // - Arc::from_raw is only called once on this pointer
+
+ // Unwrap nested Arc<dyn Array> if present (zero clones if not nested)
Review Comment:
If I understand correctly, the SO question is trying to go from `Arc<dyn
Foo>` to `Arc<dyn Any>`. The two solutions are:
* use trait upcasting
* define an extension trait with a helper method that receives `Arc<Self>`
The former requires `Foo: Any + 'static` as well as the unstable
trait-upcasting feature. Even if the feature stabilizes, we still have the
problem that `Array` does _not_ satisfy `Any + 'static`.
The latter I _thought_ would make the extension trait not dyn-compatible...
but the code in that accepted SO answer seems to compile... let me look into
that and get back to you.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]