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

feat(generator/rust): improve setters #844

Merged
merged 2 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 55 additions & 10 deletions generator/internal/language/rusttemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,14 @@ type rustMessageAnnotation struct {
MessageAttributes []string
DocLines []string
HasNestedTypes bool
BasicFields []*api.Field
// All the fields except OneOfs.
BasicFields []*api.Field
// The subset of `BasicFields` that are neither maps, nor repeated.
SingularFields []*api.Field
// The subset of `BasicFields` that are repeated (`Vec<T>` in Rust).
RepeatedFields []*api.Field
// The subset of `BasicFields` that are maps (`HashMap<K, V>` in Rust).
MapFields []*api.Field
codyoss marked this conversation as resolved.
Show resolved Hide resolved
// If true, this is a synthetic message, some generation is skipped for
// synthetic messages
HasSyntheticFields bool
Expand Down Expand Up @@ -142,12 +149,18 @@ type rustFieldAnnotations struct {
SetterName string
// In Rust, fields that appear in a OneOf also appear as a enum branch.
// These must be in `PascalCase`.
BranchName string
BranchName string
// The fully qualified name of the containing message.
FQMessageName string
DocLines []string
Attributes []string
FieldType string
PrimitiveFieldType string
AddQueryParameter string
// For fields that are maps, these are the type of the key and value,
// respectively.
KeyType string
ValueType string
}

type rustEnumAnnotation struct {
Expand Down Expand Up @@ -285,7 +298,7 @@ func rustAnnotateMessage(m *api.Message, state *api.APIState, deserializeWithDef
if f.Synthetic {
hasSyntheticFields = true
}
rustAnnotateField(f, state, modulePath, sourceSpecificationPackageName, packageMapping)
rustAnnotateField(f, m, state, modulePath, sourceSpecificationPackageName, packageMapping)
}
for _, f := range m.OneOfs {
rustAnnotateOneOf(f, m, state, modulePath, sourceSpecificationPackageName, packageMapping)
Expand All @@ -296,6 +309,23 @@ func rustAnnotateMessage(m *api.Message, state *api.APIState, deserializeWithDef
for _, child := range m.Messages {
rustAnnotateMessage(child, state, deserializeWithDefaults, modulePath, sourceSpecificationPackageName, packageMapping)
}

isMap := func(f *api.Field) bool {
if f.Typez != api.MESSAGE_TYPE {
return false
}
if m, ok := state.MessageByID[f.TypezID]; ok {
return m.IsMap
}
return false
}
isRepeated := func(f *api.Field) bool {
return f.Repeated && !isMap(f)
}

basicFields := filterSlice(m.Fields, func(f *api.Field) bool {
return !f.IsOneOf
})
m.Codec = &rustMessageAnnotation{
Name: rustToPascal(m.Name),
ModuleName: rustToSnake(m.Name),
Expand All @@ -304,8 +334,15 @@ func rustAnnotateMessage(m *api.Message, state *api.APIState, deserializeWithDef
DocLines: rustFormatDocComments(m.Documentation, state, modulePath, sourceSpecificationPackageName, packageMapping),
MessageAttributes: rustMessageAttributes(deserializeWithDefaults),
HasNestedTypes: hasNestedTypes(m),
BasicFields: filterSlice(m.Fields, func(s *api.Field) bool {
return !s.IsOneOf
BasicFields: basicFields,
SingularFields: filterSlice(basicFields, func(f *api.Field) bool {
return !isRepeated(f) && !isMap(f)
}),
RepeatedFields: filterSlice(m.Fields, func(f *api.Field) bool {
return isRepeated(f)
}),
MapFields: filterSlice(m.Fields, func(f *api.Field) bool {
return isMap(f)
codyoss marked this conversation as resolved.
Show resolved Hide resolved
}),
HasSyntheticFields: hasSyntheticFields,
}
Expand Down Expand Up @@ -364,20 +401,28 @@ func rustAnnotateOneOf(oneof *api.OneOf, message *api.Message, state *api.APISta
}
}

func rustAnnotateField(field *api.Field, state *api.APIState, modulePath, sourceSpecificationPackageName string, packageMapping map[string]*rustPackage) {
if field == nil {
return
}
field.Codec = &rustFieldAnnotations{
func rustAnnotateField(field *api.Field, message *api.Message, state *api.APIState, modulePath, sourceSpecificationPackageName string, packageMapping map[string]*rustPackage) {
ann := &rustFieldAnnotations{
FieldName: rustToSnake(field.Name),
SetterName: rustToSnakeNoMangling(field.Name),
FQMessageName: rustFQMessageName(message, modulePath, sourceSpecificationPackageName, packageMapping),
codyoss marked this conversation as resolved.
Show resolved Hide resolved
BranchName: rustToPascal(field.Name),
DocLines: rustFormatDocComments(field.Documentation, state, modulePath, sourceSpecificationPackageName, packageMapping),
Attributes: rustFieldAttributes(field, state),
FieldType: rustFieldType(field, state, false, modulePath, sourceSpecificationPackageName, packageMapping),
PrimitiveFieldType: rustFieldType(field, state, true, modulePath, sourceSpecificationPackageName, packageMapping),
AddQueryParameter: rustAddQueryParameter(field),
}
field.Codec = ann
if field.Typez != api.MESSAGE_TYPE {
return
}
mapMessage, ok := state.MessageByID[field.TypezID]
if !ok || !mapMessage.IsMap {
return
}
ann.KeyType = rustMapType(mapMessage.Fields[0], state, modulePath, sourceSpecificationPackageName, packageMapping)
ann.ValueType = rustMapType(mapMessage.Fields[1], state, modulePath, sourceSpecificationPackageName, packageMapping)
}

func rustAnnotateEnum(e *api.Enum, state *api.APIState, modulePath, sourceSpecificationPackageName string, packageMapping map[string]*rustPackage) {
Expand Down
33 changes: 30 additions & 3 deletions generator/internal/language/templates/rust/common/message.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,41 @@ pub struct {{Codec.Name}} {
}

impl {{Codec.Name}} {
{{#Codec.BasicFields}}
{{#Codec.SingularFields}}

/// Sets the value of `{{Codec.FieldName}}`.
/// Sets the value of [{{Codec.FieldName}}][{{Codec.FQMessageName}}::{{Codec.SetterName}}].
pub fn set_{{Codec.SetterName}}<T: std::convert::Into<{{{Codec.FieldType}}}>>(mut self, v: T) -> Self {
self.{{Codec.FieldName}} = v.into();
self
}
{{/Codec.BasicFields}}
{{/Codec.SingularFields}}
{{#Codec.RepeatedFields}}

/// Sets the value of [{{Codec.FieldName}}][{{Codec.FQMessageName}}::{{Codec.SetterName}}].
pub fn set_{{Codec.SetterName}}<T, V>(mut self, v: T) -> Self
where
T: std::iter::IntoIterator<Item = V>,
V: std::convert::Into<{{{Codec.PrimitiveFieldType}}}>
{
use std::iter::Iterator;
self.{{Codec.FieldName}} = v.into_iter().map(|i| i.into()).collect();
self
}
{{/Codec.RepeatedFields}}
{{#Codec.MapFields}}

/// Sets the value of [{{Codec.FieldName}}][{{Codec.FQMessageName}}::{{Codec.SetterName}}].
pub fn set_{{Codec.SetterName}}<T, K, V>(mut self, v: T) -> Self
where
T: std::iter::IntoIterator<Item = (K, V)>,
K: std::convert::Into<{{{Codec.KeyType}}}>,
V: std::convert::Into<{{{Codec.ValueType}}}>,
{
use std::iter::Iterator;
self.{{Codec.FieldName}} = v.into_iter().map(|(k, v)| (k.into(), v.into())).collect();
self
}
{{/Codec.MapFields}}
{{#OneOfs}}

/// Sets the value of `{{Codec.FieldName}}`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,40 @@ pub mod {{NameToSnake}} {
lro::new_poller(polling_policy, polling_backoff_policy, start, query)
}
{{/OperationInfo}}
{{#InputType.Codec.BasicFields}}
{{#InputType.Codec.SingularFields}}

/// Sets the value of `{{Codec.FieldName}}`.
/// Sets the value of [{{Codec.FieldName}}][{{Codec.FQMessageName}}::{{Codec.SetterName}}].
pub fn set_{{Codec.SetterName}}<T: Into<{{{Codec.FieldType}}}>>(mut self, v: T) -> Self {
self.0.request.{{Codec.FieldName}} = v.into();
self
}
{{/InputType.Codec.BasicFields}}
{{/InputType.Codec.SingularFields}}
{{#InputType.Codec.RepeatedFields}}

/// Sets the value of [{{Codec.FieldName}}][{{Codec.FQMessageName}}::{{Codec.SetterName}}].
pub fn set_{{Codec.SetterName}}<T, V>(mut self, v: T) -> Self
where
T: std::iter::IntoIterator<Item = V>,
V: std::convert::Into<{{{Codec.PrimitiveFieldType}}}>
{
use std::iter::Iterator;
self.0.request.{{Codec.FieldName}} = v.into_iter().map(|i| i.into()).collect();
self
}
{{/InputType.Codec.RepeatedFields}}
{{#InputType.Codec.MapFields}}

/// Sets the value of [{{Codec.FieldName}}][{{Codec.FQMessageName}}::{{Codec.SetterName}}].
pub fn set_{{Codec.SetterName}}<T, K, V>(mut self, v: T) -> Self
where
T: std::iter::IntoIterator<Item = (K, V)>,
K: std::convert::Into<{{{Codec.KeyType}}}>,
V: std::convert::Into<{{{Codec.ValueType}}}>,
{
self.0.request.{{Codec.FieldName}} = v.into_iter().map(|(k, v)| (k.into(), v.into())).collect();
self
}
{{/InputType.Codec.MapFields}}
{{#InputType.OneOfs}}

/// Sets the value of `{{Codec.FieldName}}`.
Expand Down
Loading
Loading