blob: 6107a5572c71815618b50aafb372d0f77dda0f94 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file implements outputLanguage for Rust
package source_generator
import (
"fmt"
"sort"
)
type Rust struct{}
func (Rust) getCommentPrefix() string { return "//" }
func (Rust) supportsTypeAlias() bool { return true }
func (Rust) writeExtraHeader(so *sourceOutputter, projectName, customerName string, namespaces []string) {
}
func (Rust) writeExtraFooter(so *sourceOutputter, projectName, customerName string, namespaces []string) {
}
// See: https://doc.rust-lang.org/reference/keywords.html
var rustIdents = [...]string{
"as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for", "if",
"impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", "self",
"Self", "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where", "while",
"async", "await", "dyn", "abstract", "become", "box", "do", "final", "macro", "override", "priv",
"typeof", "unsized", "virtual", "yield", "try",
}
func escapeIdent(value string) string {
for _, ident := range rustIdents {
if ident == value {
return fmt.Sprintf("r#%s", value)
}
}
return value
}
func (Rust) writeEnumBegin(so *sourceOutputter, name ...string) {
so.writeLine("#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]")
so.writeLineFmt("pub enum %s {", toPascalCase(name...))
}
func (Rust) writeEnumEntry(so *sourceOutputter, value uint32, name ...string) {
so.writeLineFmt(" %s = %d,", toPascalCase(name...), value)
}
func (Rust) writeEnumAliasesBegin(so *sourceOutputter, name ...string) {
so.writeLine("}")
so.writeLineFmt("impl %s {", toPascalCase(name...))
}
func (Rust) writeEnumAlias(so *sourceOutputter, name, from, to []string) {
so.writeLine(" #[allow(non_upper_case_globals)]")
so.writeLineFmt(" pub const %s: %s = %s::%s;", toPascalCase(to...), toPascalCase(name...), toPascalCase(name...), toPascalCase(from...))
}
func (Rust) writeEnumEnd(so *sourceOutputter, name ...string) {
so.writeLine("}")
so.writeLine("")
so.writeLineFmt("impl cobalt_client::traits::AsEventCode for %s {", toPascalCase(name...))
so.writeLine(" fn as_event_code(&self) -> u32 {")
so.writeLine(" *self as u32")
so.writeLine(" }")
so.writeLine("}")
}
// We don't alias Enums in rust, since this can easily be accomplished with a
// use EnumName::*;
func (Rust) writeEnumExport(so *sourceOutputter, enumName, name []string) {}
func (Rust) writeTypeAlias(so *sourceOutputter, from, to []string) {
so.writeLineFmt("pub use %s as %s;", toPascalCase(from...), toPascalCase(to...))
}
func (Rust) writeNamespacesBegin(so *sourceOutputter, namespaces []string, outputFilename string) {
if len(namespaces) > 0 {
for _, ns := range namespaces {
so.writeLineFmt("pub mod %s {", escapeIdent(toSnakeCase(ns)))
}
}
}
func (Rust) writeNamespacesEnd(so *sourceOutputter, namespaces []string, outputFilename string) {
if len(namespaces) > 0 {
for _, _ = range namespaces {
so.writeLine("}")
}
}
}
func (Rust) writeConstUint32(so *sourceOutputter, value uint32, name ...string) {
so.writeLineFmt("pub const %s: u32 = %d;", toUpperSnakeCase(name...), value)
}
func (Rust) writeConstInt64(so *sourceOutputter, value int64, name ...string) {
so.writeLineFmt("pub const %s: i64 = %d;", toUpperSnakeCase(name...), value)
}
func (Rust) writeConstMap(so *sourceOutputter, value map[uint32]string, name ...string) {
var keys []uint32
for k := range value {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
so.writeLineFmt("pub const %s: [(&'static str, u32); %d] = [", toUpperSnakeCase(name...), len(keys))
for _, id := range keys {
dimensionValue := value[id]
so.writeLineFmt(" (\"%s\", %d),", dimensionValue, id)
}
so.writeLineFmt("];")
}
func (Rust) writeStringConstant(so *sourceOutputter, value string, name ...string) {
so.writeLineFmt("pub const %s: &str = \"%s\";", toUpperSnakeCase(name...), value)
}
func (Rust) writeStructBegin(so *sourceOutputter, name ...string) {
so.writeLine("#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]")
so.writeLineFmt("pub struct %s {", toPascalCase(name...))
}
func (Rust) writeStructField(so *sourceOutputter, name, typeName []string) {
so.writeLineFmt(" pub %s: %s,", escapeIdent(toSnakeCase(name...)), escapeIdent(toPascalCase(typeName...)))
}
func (Rust) writeToVectorMethod(so *sourceOutputter, structName []string, fields [][]string) {
so.writeLine("}")
so.writeLine("")
so.writeLineFmt("impl cobalt_client::traits::AsEventCodes for %s {", toPascalCase(structName...))
so.writeLine(" fn as_event_codes(&self) -> Vec<u32> {")
so.writeLine(" use cobalt_client::traits::AsEventCode;")
so.writeLine(" vec![")
for _, field := range fields {
so.writeLineFmt(" self.%s.as_event_code(),", escapeIdent(toSnakeCase(field...)))
}
so.writeLine(" ]")
so.writeLine(" }")
}
func (Rust) writeStructEnd(so *sourceOutputter) {
so.writeLine("}")
}
// varName will be the name of the variable containing the base64-encoded serialized proto.
// namespace is a list of nested namespaces inside of which the variable will be defined.
// If forTesting is true, a constant will be generated for each report ID, based on the report's name.
func RustOutputFactory(varName string, namespace []string, options generatorOptions) OutputFormatter {
return newSourceOutputterWithNamespaces(Rust{}, varName, namespace, options).getOutputFormatter()
}