From c462bc5d36d6bd1bc44a1ce12bca6e6427506529 Mon Sep 17 00:00:00 2001 From: Carlos O'Ryan Date: Mon, 4 Nov 2024 22:04:16 +0000 Subject: [PATCH] impl(generator): Rust uses strings for enum values (#88) We decided to use strings for enum values, as the transport will be HTTP + JSON. The generator creates some helper constants in a properly named module, that prevents typos. --- .../genclient/language/internal/rust/rust.go | 14 ++++++------- generator/internal/genclient/templatedata.go | 4 ++++ generator/templates/rust/enum.mustache | 13 +++++++----- .../testdata/rust/gclient/golden/model.rs | 20 +++++++++++-------- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/generator/internal/genclient/language/internal/rust/rust.go b/generator/internal/genclient/language/internal/rust/rust.go index b1ca9840..87a5902b 100644 --- a/generator/internal/genclient/language/internal/rust/rust.go +++ b/generator/internal/genclient/language/internal/rust/rust.go @@ -163,16 +163,14 @@ func (c *Codec) FQEnumName(e *genclient.Enum, _ *genclient.APIState) string { return c.messageScopeName(e.Parent) + "::" + c.ToPascal(e.Name) } -func (c *Codec) EnumValueName(e *genclient.EnumValue, state *genclient.APIState) string { - if e.Parent.Parent != nil { - return c.MessageName(e.Parent.Parent, state) + "_" + strcase.ToCamel(e.Name) - } - return c.ToPascal(e.Name) +func (c *Codec) EnumValueName(e *genclient.EnumValue, _ *genclient.APIState) string { + // The Protobuf naming convention is to use SCREAMING_SNAKE_CASE, we do not + // need to change anything for Rust + return EscapeKeyword(e.Name) } -func (c *Codec) FQEnumValueName(v *genclient.EnumValue, _ *genclient.APIState) string { - // TODO(#76) - these will be `const` strings and therefore should be SNAKE_UPPERCASE. - return c.enumScopeName(v.Parent) + "::" + c.ToSnake(v.Name) +func (c *Codec) FQEnumValueName(v *genclient.EnumValue, state *genclient.APIState) string { + return fmt.Sprintf("%s::%s::%s", c.enumScopeName(v.Parent), c.ToSnake(v.Parent.Name), c.EnumValueName(v, state)) } func (c *Codec) BodyAccessor(m *genclient.Method, state *genclient.APIState) string { diff --git a/generator/internal/genclient/templatedata.go b/generator/internal/genclient/templatedata.go index 21ffe624..5b37c88e 100644 --- a/generator/internal/genclient/templatedata.go +++ b/generator/internal/genclient/templatedata.go @@ -249,6 +249,10 @@ func (e *enum) Name() string { return e.c.EnumName(e.s, e.state) } +func (e *enum) NameSnakeCase() string { + return e.c.ToSnake(e.c.EnumName(e.s, e.state)) +} + func (e *enum) DocLines() []string { ss := strings.Split(e.s.Documentation, "\n") for i := range ss { diff --git a/generator/templates/rust/enum.mustache b/generator/templates/rust/enum.mustache index c1359e45..3f269724 100644 --- a/generator/templates/rust/enum.mustache +++ b/generator/templates/rust/enum.mustache @@ -1,13 +1,16 @@ - +{{#DocLines}} +/// {{{.}}} +{{/DocLines}} #[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct {{Name}}(i32); +pub struct {{Name}}(String); -impl {{Name}} { +/// Useful constants to work with [{{Name}}]({{Name}}) +pub mod {{NameSnakeCase}} { {{#Values}} {{#DocLines}} /// {{{.}}} {{/DocLines}} - pub const {{Name}}: {{EnumType}} = {{EnumType}}({{Number}}); + pub const {{Name}}: &str = "{{Name}}"; {{/Values}} -} \ No newline at end of file +} diff --git a/generator/testdata/rust/gclient/golden/model.rs b/generator/testdata/rust/gclient/golden/model.rs index 61e9bbc5..36260ff4 100644 --- a/generator/testdata/rust/gclient/golden/model.rs +++ b/generator/testdata/rust/gclient/golden/model.rs @@ -174,31 +174,35 @@ pub struct SecretVersion { /// Defines additional types related to SecretVersion pub mod secret_version { - + /// The state of a + /// [SecretVersion][google.cloud.secretmanager.v1.SecretVersion], indicating if + /// it can be accessed. #[derive(Clone, Debug, Default, Deserialize, Serialize)] - pub struct State(i32); + pub struct State(String); - impl State { + /// Useful constants to work with [State](State) + pub mod state { /// Not specified. This value is unused and invalid. - pub const SecretVersion_StateUnspecified: State = State(0); + pub const STATE_UNSPECIFIED: &str = "STATE_UNSPECIFIED"; /// The [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] may be /// accessed. - pub const SecretVersion_Enabled: State = State(1); + pub const ENABLED: &str = "ENABLED"; /// The [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] may not /// be accessed, but the secret data is still available and can be placed /// back into the /// [ENABLED][google.cloud.secretmanager.v1.SecretVersion.State.ENABLED] /// state. - pub const SecretVersion_Disabled: State = State(2); + pub const DISABLED: &str = "DISABLED"; /// The [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] is /// destroyed and the secret data is no longer stored. A version may not /// leave this state once entered. - pub const SecretVersion_Destroyed: State = State(3); - }} + pub const DESTROYED: &str = "DESTROYED"; + } +} /// A policy that defines the replication and encryption configuration of data. #[derive(Clone, Debug, Default, Deserialize, Serialize)]