Skip to content

Commit 892f42b

Browse files
authored
feat(sidekick): add default Rust features option (#2562)
In Rust sometimes we add per-service features to only compile the services one needs. Before this change, all the services are enabled by default. That won't fly for the Compute API, there are too many services.
1 parent 7eee2b5 commit 892f42b

File tree

5 files changed

+154
-5
lines changed

5 files changed

+154
-5
lines changed

internal/sidekick/internal/rust/annotate.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,13 @@ type modelAnnotations struct {
4949
// If true, disable rustdoc warnings known to be triggered by our generated
5050
// documentation.
5151
DisabledRustdocWarnings []string
52-
// Sets the default system parameters
52+
// Sets the default system parameters.
5353
DefaultSystemParameters []systemParameter
54-
// Enables per-service features
54+
// Enables per-service features.
5555
PerServiceFeatures bool
56+
// The set of default features, only applicable if `PerServiceFeatures` is
57+
// true.
58+
DefaultFeatures []string
5659
// A list of additional modules loaded by the `lib.rs` file.
5760
ExtraModules []string
5861
// If true, at lease one service has a method we cannot wrap (yet).
@@ -666,6 +669,10 @@ func (c *codec) addFeatureAnnotations(model *api.API, ann *modelAnnotations) {
666669
annotation.FeatureGatesOp = "all"
667670
annotation.FeatureGates = allFeatures
668671
}
672+
ann.DefaultFeatures = c.defaultFeatures
673+
if ann.DefaultFeatures == nil {
674+
ann.DefaultFeatures = allFeatures
675+
}
669676
}
670677

671678
// packageToModuleName maps "google.foo.v1" to "google::foo::v1".
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package rust
16+
17+
import (
18+
"testing"
19+
20+
"github.com/google/go-cmp/cmp"
21+
"github.com/googleapis/librarian/internal/sidekick/internal/api"
22+
)
23+
24+
func TestDefaultFeatures(t *testing.T) {
25+
for _, test := range []struct {
26+
Options map[string]string
27+
Want []string
28+
}{
29+
{
30+
Options: map[string]string{
31+
"per-service-features": "true",
32+
},
33+
Want: []string{"service-0", "service-1"},
34+
},
35+
{
36+
Options: map[string]string{
37+
"per-service-features": "false",
38+
},
39+
Want: nil,
40+
},
41+
{
42+
Options: map[string]string{
43+
"per-service-features": "true",
44+
"default-features": "service-1",
45+
},
46+
Want: []string{"service-1"},
47+
},
48+
{
49+
Options: map[string]string{
50+
"per-service-features": "true",
51+
"default-features": "",
52+
},
53+
Want: []string{},
54+
},
55+
} {
56+
model := newTestAnnotateModelAPI()
57+
codec, err := newCodec("protobuf", test.Options)
58+
if err != nil {
59+
t.Fatal(err)
60+
}
61+
got := annotateModel(model, codec)
62+
t.Logf("Options=%v", test.Options)
63+
if diff := cmp.Diff(test.Want, got.DefaultFeatures); diff != "" {
64+
t.Errorf("mismatch (-want, +got):\n%s", diff)
65+
}
66+
}
67+
}
68+
69+
func newTestAnnotateModelAPI() *api.API {
70+
service0 := &api.Service{
71+
Name: "Service0",
72+
ID: "..Service0",
73+
Methods: []*api.Method{
74+
{
75+
Name: "get",
76+
ID: "..Service0.get",
77+
InputTypeID: ".google.protobuf.Empty",
78+
OutputTypeID: ".google.protobuf.Empty",
79+
PathInfo: &api.PathInfo{
80+
Bindings: []*api.PathBinding{
81+
{
82+
Verb: "GET",
83+
PathTemplate: api.NewPathTemplate().WithLiteral("resource"),
84+
},
85+
},
86+
},
87+
},
88+
},
89+
}
90+
service1 := &api.Service{
91+
Name: "Service1",
92+
ID: "..Service1",
93+
Methods: []*api.Method{
94+
{
95+
Name: "get",
96+
ID: "..Service1.get",
97+
InputTypeID: ".google.protobuf.Empty",
98+
OutputTypeID: ".google.protobuf.Empty",
99+
PathInfo: &api.PathInfo{
100+
Bindings: []*api.PathBinding{
101+
{
102+
Verb: "GET",
103+
PathTemplate: api.NewPathTemplate().WithLiteral("resource"),
104+
},
105+
},
106+
},
107+
},
108+
},
109+
}
110+
model := api.NewTestAPI(
111+
[]*api.Message{},
112+
[]*api.Enum{},
113+
[]*api.Service{service0, service1})
114+
api.CrossReference(model)
115+
return model
116+
}

internal/sidekick/internal/rust/codec.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ func newCodec(specificationFormat string, options map[string]string) (*codec, er
132132
return nil, fmt.Errorf("cannot convert `per-service-features` value %q to boolean: %w", definition, err)
133133
}
134134
codec.perServiceFeatures = value
135+
case key == "default-features":
136+
if definition == "" {
137+
codec.defaultFeatures = []string{}
138+
} else {
139+
codec.defaultFeatures = strings.Split(definition, ",")
140+
}
135141
case key == "detailed-tracing-attributes":
136142
value, err := strconv.ParseBool(definition)
137143
if err != nil {
@@ -263,6 +269,8 @@ type codec struct {
263269
includeGrpcOnlyMethods bool
264270
// If true, the generator will produce per-client features.
265271
perServiceFeatures bool
272+
// If not empty, and if `perServiceFeatures` is true, the default features
273+
defaultFeatures []string
266274
// If true, the generated code includes detailed tracing attributes on HTTP
267275
// requests. This feature flag exists to reduce unexpected changes to the
268276
// generated code until the feature is ready and well-tested.

internal/sidekick/internal/rust/codec_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,24 @@ func TestParseOptions(t *testing.T) {
206206
c.perServiceFeatures = true
207207
},
208208
},
209+
{
210+
Format: "protobuf",
211+
Options: map[string]string{
212+
"default-features": "a,b,c",
213+
},
214+
Update: func(c *codec) {
215+
c.defaultFeatures = []string{"a", "b", "c"}
216+
},
217+
},
218+
{
219+
Format: "protobuf",
220+
Options: map[string]string{
221+
"default-features": "",
222+
},
223+
Update: func(c *codec) {
224+
c.defaultFeatures = []string{}
225+
},
226+
},
209227
{
210228
Format: "protobuf",
211229
Options: map[string]string{

internal/sidekick/internal/rust/templates/common/Cargo.toml.mustache

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ publish = false
3636

3737
[features]
3838
default = [
39-
{{#Codec.Services}}
40-
"{{Codec.FeatureName}}",
41-
{{/Codec.Services}}
39+
{{#Codec.DefaultFeatures}}
40+
"{{{.}}}",
41+
{{/Codec.DefaultFeatures}}
4242
]
4343
{{#Codec.Services}}
4444
# Enables `client::{{Codec.Name}}` and all the types it depends on.

0 commit comments

Comments
 (0)