Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

node/bindnode: allow nilable types for IPLD optional/nullable #401

Merged
merged 1 commit into from
Apr 26, 2022
Merged

node/bindnode: allow nilable types for IPLD optional/nullable #401

merged 1 commit into from
Apr 26, 2022

Conversation

mvdan
Copy link
Contributor

@mvdan mvdan commented Apr 10, 2022

(see commit message)

Fixes #378.

@mvdan
Copy link
Contributor Author

mvdan commented Apr 10, 2022

FYI @rvagg @BigLep

@masih @hannahhoward (and Rod) please test this in projects like graphsync and storetheindex, since I believe those use optional/nullable with bindnode and had run into the limitation with pointers. This should work, but it's best to double check there are no known regressions before it's merged.

For simplicity, bindnode used to always require a pointer to represent
optional or nullable IPLD types. This is because we need an extra bit to
store whether the value is absent or null.

However, some Go types can already store a "nil" value to represent that
bit without needing that extra pointer. Most notably:

	[]T            versus *[]T
	map[K]V        versus *map[K]V
	datamodel.Node versus *datamodel.Node

Avoiding the extra pointer makes the types easier for humans to deal
with, and it also avoids a potential footgun due to the extra "nil"
state that bindnode doesn't actually use.

Note that we still require pointers for "optional nullable" struct
fields, as those need two extra bits. A TODO is left for that edge case.

Fixes #378.
@BigLep BigLep requested a review from rvagg April 19, 2022 22:04
qt.Assert(t, err, qt.Not(qt.IsNil))
}
})
}
}
}

func nilable(kind reflect.Kind) bool {
Copy link
Member

Choose a reason for hiding this comment

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

do you need this, or can you look at the second return of ptrOrNilable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The funcs are unexported so they cannot be shared between the test and non-test packages - that's how I arrived at the smaller copy. Any other alternative is more lines of code AFAICT.

if goType.Kind() != reflect.Ptr {
doPanic("union members must be pointers")
if ptr, nilable := ptrOrNilable(goType.Kind()); !nilable {
doPanic("union members must be nilable")
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is the ideal error here - it's talking schema language about a Go struct, maybe that's the best we have? but istm that this would be better stated as "must be pointers or interfaces".

Not blocking, just noting that it's weird encountering this error in the test when it's refering to the Go type.

Copy link
Member

@rvagg rvagg left a comment

Choose a reason for hiding this comment

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

awesome
you're already missed @mvdan, such nice code to review

@rvagg rvagg merged commit e69ddc7 into ipld:master Apr 26, 2022
@mvdan mvdan deleted the bindnode-pointer-like branch May 15, 2022 10:19
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.

node/bindnode: allow nilable types instead of a pointer for optional/nullable schemas
3 participants