Skip to content

feat: Implement Scalar::From<HashMap<K, V>> - #1541

Merged
Fokko merged 15 commits into
delta-io:mainfrom
Fokko:fd-i-love-macros
Jan 14, 2026
Merged

feat: Implement Scalar::From<HashMap<K, V>>#1541
Fokko merged 15 commits into
delta-io:mainfrom
Fokko:fd-i-love-macros

Conversation

@Fokko

@Fokko Fokko commented Dec 4, 2025

Copy link
Copy Markdown
Collaborator

This PR extends the IntoEngineData derive macro to work with structs containing HashMap and Option<Vec<T>> fields by implementing the necessary TryFrom conversions for Scalar. This is foundational work to support reading arbitrary fields from CommitInfo.

This resolves #1083.

What changes are proposed in this pull request?

How was this change tested?

@codecov

codecov Bot commented Dec 4, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.57143% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.92%. Comparing base (f8106c5) to head (9dc8ecf).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
kernel/src/expressions/scalars.rs 75.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1541      +/-   ##
==========================================
- Coverage   83.93%   83.92%   -0.02%     
==========================================
  Files         120      120              
  Lines       32962    32930      -32     
  Branches    32962    32930      -32     
==========================================
- Hits        27668    27637      -31     
- Misses       3925     3927       +2     
+ Partials     1369     1366       -3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@emkornfield

Copy link
Copy Markdown
Collaborator

@Fokko could you fill in the description of the PR please when you get a chance.

Comment thread kernel/src/error.rs
}
}

impl From<Infallible> for Error {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not exactly clear what this is doing here, or why we need it? Could you add a comment?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good one, I've added a comment, let me know if it makes sense 👍

fn try_from(opt: Option<Vec<T>>) -> Result<Self, Self::Error> {
match opt {
Some(vec) => vec.try_into(),
None => Ok(Self::Null(ArrayType::new(T::to_data_type(), false).into())),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the false here? Not nullable?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would this depend on if T is an Option?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly! So, if T is wrapped with an Option, then it needs to be set to true. For example, here:

impl<T> TryFrom<Vec<Option<T>>> for Scalar
where
T: Into<Scalar> + ToDataType,
{
type Error = Error;
fn try_from(vec: Vec<Option<T>>) -> Result<Self, Self::Error> {
let array_type = ArrayType::new(T::to_data_type(), true);
let array_data = ArrayData::try_new(array_type, vec)?;
Ok(array_data.into())
}
}

T itself cannot be an option, since there is no corresponding Null scalar, so we can assume that they are all not-null.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hrmm, we already have:

  • impl<T> TryFrom<Vec<T>> for Scalar
  • impl<K, V> TryFrom<HashMap<K, Option<V>>> for Scalar
  • impl<T: Into<Scalar> + ToDataType> From<Option<T>> for Scalar

If we just added impl<T:TryInto<Scalar> + ToDataType> TryFrom<Option<T>> for Scalar would that get us what we want without having to special case Vec and HashMap?

@Fokko
Fokko requested a review from emkornfield December 9, 2025 17:26

@nicklan nicklan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, one more suggestion

Comment thread kernel/src/actions/mod.rs
in_commit_timestamp,
operation: Some(operation.unwrap_or_else(|| UNKNOWN_OPERATION.to_string())),
operation_parameters: None,
operation_parameters: Some(HashMap::new()),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this change?

fn try_from(opt: Option<Vec<T>>) -> Result<Self, Self::Error> {
match opt {
Some(vec) => vec.try_into(),
None => Ok(Self::Null(ArrayType::new(T::to_data_type(), false).into())),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hrmm, we already have:

  • impl<T> TryFrom<Vec<T>> for Scalar
  • impl<K, V> TryFrom<HashMap<K, Option<V>>> for Scalar
  • impl<T: Into<Scalar> + ToDataType> From<Option<T>> for Scalar

If we just added impl<T:TryInto<Scalar> + ToDataType> TryFrom<Option<T>> for Scalar would that get us what we want without having to special case Vec and HashMap?

@Fokko

Fokko commented Jan 8, 2026

Copy link
Copy Markdown
Collaborator Author

@nicklan

Unfortunately, this approach doesn't work due to Rust's trait coherence rules. The standard library has a blanket impl<T, U> TryFrom<U> for T where U: Into<T> which already provides TryFrom<Option<T>> for any T that has From<Option<T>> implemented (i.e., the primitive types via our existing impl<T: Into<Scalar> + ToDataType> From<Option<T>> for Scalar).

Adding a generic impl<T: TryInto<Scalar> + ToDataType> TryFrom<Option<T>> for Scalar conflicts with this blanket impl because the compiler can't distinguish which implementation to use for types where both bounds apply.

The special-case implementations for Option<Vec<T>> and Option<HashMap<K, V>> work precisely because Vec<T> and HashMap<K, V> only implement TryInto<Scalar> (not Into<Scalar>), so there's no conflict with the blanket impl.

@Fokko
Fokko requested a review from nicklan January 8, 2026 20:37
@nicklan

nicklan commented Jan 8, 2026

Copy link
Copy Markdown
Member

The special-case implementations for Option<Vec<T>> and Option<HashMap<K, V>> work precisely because Vec<T> and HashMap<K, V> only implement TryInto<Scalar> (not Into<Scalar>), so there's no conflict with the blanket impl.

Got it, thanks for the explanation

@Fokko
Fokko merged commit 2014edb into delta-io:main Jan 14, 2026
21 of 22 checks passed
@Fokko
Fokko deleted the fd-i-love-macros branch January 14, 2026 11:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Scalar::From<HashMap<K, V>>

3 participants