-
Notifications
You must be signed in to change notification settings - Fork 15
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
add: custom types #45
Draft
fdymylja
wants to merge
4
commits into
main
Choose a base branch
from
fdymylja/custom-type
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package protoc | ||
|
||
import ( | ||
"github.com/cosmos/cosmos-proto/cosmos_proto" | ||
"github.com/cosmos/cosmos-proto/generator" | ||
"google.golang.org/protobuf/compiler/protogen" | ||
"google.golang.org/protobuf/proto" | ||
"strings" | ||
) | ||
|
||
func isCustomType(field *protogen.Field) bool { | ||
fd := field.Desc | ||
t := proto.GetExtension(fd.Options(), cosmos_proto.E_GoType).(string) | ||
return t != "" | ||
} | ||
|
||
func customFieldType(g *generator.GeneratedFile, field *protogen.Field) string { | ||
if field.Desc.IsList() || field.Desc.IsMap() { | ||
panic("invalid custom type") // TODO(fdymylja): better err msg | ||
} | ||
t := proto.GetExtension(field.Desc.Options(), cosmos_proto.E_GoType).(string) | ||
switch { | ||
case !strings.Contains(t, "."): | ||
return "*" + t | ||
default: | ||
s := strings.Split(t, ".") | ||
typeName := s[len(s)-1] | ||
pkg := protogen.GoImportPath(strings.Join(s[0:len(s)-1], ".")) | ||
g.Import(pkg) | ||
return "*" + g.QualifiedGoIdent(pkg.Ident(typeName)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure we need to make it this complex. On one hand this allows caching of the
protoreflect.Value
+ custom type, but feels like it mixes too many concerns. Can you say a little bit more about the use case for messages andMutable
?My thinking was that we only handle
string
orbytes
types for now because those are the only cases we have with a very simple two method Unmarshal/Marshal interface, and that a scalar can only work with one proto type (string or bytes)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can see it in this way:
Do we want a custom type to be capable of overriding a message (ex we want to override anypb.Any with pulsar.Any) ?
If this is the intention then this is the only API which does not require multiple implementations of custom type logic that can serve all purposes.
If not then we can simplify by removing unmarshal/marshal/size inputs and Mutable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So as we discussed I don't think we want to extend this for full Message type overriding (for Any's we can just replace the type name).
For simple scalars, we could use something like I described in #2 for
CustomStringType
orCustomBytesType
or even something as simple as:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doing one custom type for each primitive is going to be a big chunk of work codegen wise (basically we need one extra check for each kind and for each method), this is why I was going for a more generalized interface. Plus custom types are going to be rare and I think they're an advanced level, so I suppose someone creating one is fully aware of protobuf semantics (like if i am customizing a string then i know bytes that are being passed are those of a string).
What if we simplified the current custom type interface to this:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which approach from #2 are you thinking of going with? why do we need both Unmarshal/Marshal + Set/Get? I'm not clear as to why we couldn't deal everything with Set/Get? With Unmarshal/Marshal the type doesn't know if it was passed a string, bytes or int64 say so it's less type safe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those methods are needed for Protoreflect.Clear/Has/Range, I need to signal to custom types that they need to be unset/cleared and I need to have a way to know if they're set or not.
Size is needed for Marshal to compute the actual size.
I wouldn't need those if custom types were simply aliases of primitives, but since we plan to substitute string with a struct (case of sdk.Int for example), we need those methods otherwise the code wouldn't know how to unset them.
Using nil is not viable (in case of fields substituted by structs) because they would break proto presence (if a type is not: optional, repeated, map or message then we cannot determine presence) - and also if we wanted to use nil then we'd need custom logic for struct custom types and for example non struct ones (Such as address being a string converted into []byte)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, but if we go with the second approach in #2 we don't need those.
I guess I'm thinking with whichever approach we take we do want the underlying proto value to get cached either by the proto message itself or the custom type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using the 1st approach is simpler to implement (from codegen perspective).
second approach would need more time because generating that logic is a lot more complex, and needs to be handled with a case by case basis in every method.
Also I think both obtain the same result, with the custom type implementation being a little harder to implement (in case 1) - but I think that's fine, I don't expect every dev to want to implement its own custom type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also another reason I'd go with 1) is because in the sdk that's how we deal with custom types currently. I think the API is more dev friendly and less breaking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you think it's reasonable to expect custom types to cache the
protoreflect.Value
?why is this the case? it just adds two fields plus a getter/setter pair without impacting any of the other marshaling/protoreflect code