blob: 30459fa04314db997cbd8fbbae134591a860bb67 [file] [log] [blame]
// Copyright 2022 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.
use crate::{normalize_field_key, SourceGenError};
use cm_rust::{ConfigChecksum, ConfigDecl, ConfigField, ConfigNestedValueType, ConfigValueType};
use handlebars::{handlebars_helper, Handlebars};
use serde::Serialize;
static CC_ELF_SOURCE_TEMPLATE: &str = include_str!("../templates/cpp_elf.cc.hbs");
static H_ELF_SOURCE_TEMPLATE: &str = include_str!("../templates/cpp_elf.h.hbs");
static HELPERS_SOURCE_TEMPLATE: &str = include_str!("../templates/helpers.cc.hbs");
static TYPEDEF_SOURCE_TEMPLATE: &str = include_str!("../templates/typedef.h.hbs");
static VMO_CREATE_SOURCE_TEMPLATE: &str = include_str!("../templates/vmo_create.cc.hbs");
static VMO_PARSE_SOURCE_TEMPLATE: &str = include_str!("../templates/vmo_parse.cc.hbs");
static VMO_PARSE_HELPERS_SOURCE_TEMPLATE: &str =
include_str!("../templates/vmo_parse_helpers.cc.hbs");
pub struct CppSource {
pub cc_source: String,
pub h_source: String,
}
pub fn create_cpp_wrapper(
config_decl: &ConfigDecl,
cpp_namespace: String,
fidl_library_name: String,
) -> Result<CppSource, SourceGenError> {
let vars = TemplateVars::from_decl(config_decl, cpp_namespace, fidl_library_name);
let mut hbars = Handlebars::new();
hbars.set_strict_mode(true);
hbars.register_escape_fn(handlebars::no_escape);
hbars.register_helper("hex_byte", Box::new(hex_byte));
hbars.register_helper("is_string_vector", Box::new(is_string_vector));
hbars.register_helper("is_bool", Box::new(is_bool));
hbars.register_helper("is_vector", Box::new(is_vector));
hbars.register_helper("is_string", Box::new(is_string));
hbars.register_helper("cpp_type", Box::new(cpp_type));
hbars.register_helper("inspect_type", Box::new(inspect_type));
hbars.register_template_string("cc_source", CC_ELF_SOURCE_TEMPLATE).pretty_unwrap();
hbars.register_template_string("h_source", H_ELF_SOURCE_TEMPLATE).pretty_unwrap();
hbars.register_template_string("helpers", HELPERS_SOURCE_TEMPLATE).pretty_unwrap();
hbars.register_template_string("typedef", TYPEDEF_SOURCE_TEMPLATE).pretty_unwrap();
hbars.register_template_string("vmo_parse", VMO_PARSE_SOURCE_TEMPLATE).pretty_unwrap();
hbars.register_template_string("vmo_create", VMO_CREATE_SOURCE_TEMPLATE).pretty_unwrap();
hbars
.register_template_string("vmo_parse_helpers", VMO_PARSE_HELPERS_SOURCE_TEMPLATE)
.pretty_unwrap();
let cc_source = hbars.render("cc_source", &vars).pretty_unwrap();
let h_source = hbars.render("h_source", &vars).pretty_unwrap();
Ok(CppSource { cc_source, h_source })
}
#[derive(Debug, Serialize)]
struct TemplateVars {
header_guard: String,
cpp_namespace: String,
fidl_library_name: String,
fidl_cpp_namespace: String,
expected_checksum: Vec<u8>,
fields: Vec<Field>,
// TODO(https://fxbug.dev/42060287) delete once unified FIDL available OOT
fidl_cpp_header_prefix: String,
}
impl TemplateVars {
fn from_decl(
config_decl: &ConfigDecl,
cpp_namespace: String,
fidl_library_name: String,
) -> Self {
let cpp_namespace = cpp_namespace.replace('.', "_").replace('-', "_").to_ascii_lowercase();
let header_guard = fidl_library_name.replace('.', "_").to_ascii_uppercase();
let (fidl_cpp_namespace, fidl_cpp_header_prefix) = {
let ns = fidl_library_name.replace('.', "_").to_ascii_lowercase();
(ns.clone(), ns)
};
let ConfigChecksum::Sha256(expected_checksum) = &config_decl.checksum;
let expected_checksum = expected_checksum.to_vec();
Self {
fields: config_decl.fields.iter().map(Field::from_decl).collect(),
header_guard,
fidl_library_name,
fidl_cpp_namespace,
fidl_cpp_header_prefix,
cpp_namespace,
expected_checksum,
}
}
}
#[derive(Debug, Serialize)]
struct Field {
ident: String,
type_: ConfigValueType,
}
impl Field {
fn from_decl(field: &ConfigField) -> Self {
Field { ident: normalize_field_key(&field.key), type_: field.type_.clone() }
}
}
handlebars_helper!(hex_byte: |b: u8| format!("{:#04x}", b));
handlebars_helper!(is_string_vector: |t: ConfigValueType| matches!(t, ConfigValueType::Vector {
nested_type: ConfigNestedValueType::String { .. }, ..
}));
handlebars_helper!(is_bool: |t: ConfigValueType| matches!(t, ConfigValueType::Bool { .. }));
handlebars_helper!(is_vector: |t: ConfigValueType| matches!(t, ConfigValueType::Vector { .. }));
handlebars_helper!(is_string: |t: ConfigValueType| matches!(t, ConfigValueType::String { .. }));
handlebars_helper!(cpp_type: |t: ConfigValueType| match t {
ConfigValueType::Bool => "bool",
ConfigValueType::Uint8 => "uint8_t",
ConfigValueType::Uint16 => "uint16_t",
ConfigValueType::Uint32 => "uint32_t",
ConfigValueType::Uint64 => "uint64_t",
ConfigValueType::Int8 => "int8_t",
ConfigValueType::Int16 => "int16_t",
ConfigValueType::Int32 => "int32_t",
ConfigValueType::Int64 => "int64_t",
ConfigValueType::String { .. } => "std::string",
ConfigValueType::Vector { nested_type, .. } => match nested_type {
ConfigNestedValueType::Bool => "std::vector<bool>",
ConfigNestedValueType::Uint8 => "std::vector<uint8_t>",
ConfigNestedValueType::Uint16 => "std::vector<uint16_t>",
ConfigNestedValueType::Uint32 => "std::vector<uint32_t>",
ConfigNestedValueType::Uint64 => "std::vector<uint64_t>",
ConfigNestedValueType::Int8 => "std::vector<int8_t>",
ConfigNestedValueType::Int16 => "std::vector<int16_t>",
ConfigNestedValueType::Int32 => "std::vector<int32_t>",
ConfigNestedValueType::Int64 => "std::vector<int64_t>",
ConfigNestedValueType::String { .. } => "std::vector<std::string>",
},
});
handlebars_helper!(inspect_type: |t: ConfigValueType| match t {
ConfigValueType::Bool => "Bool",
ConfigValueType::Uint8
| ConfigValueType::Uint16
| ConfigValueType::Uint32
| ConfigValueType::Uint64 => "Uint",
ConfigValueType::Int8
| ConfigValueType::Int16
| ConfigValueType::Int32
| ConfigValueType::Int64 => "Int",
ConfigValueType::String { .. } => "String",
ConfigValueType::Vector { nested_type, .. } => match nested_type {
// inspect doesn't provide a CreateBoolArray so cast bools to uints
ConfigNestedValueType::Bool => "Uint",
ConfigNestedValueType::Uint8
| ConfigNestedValueType::Uint16
| ConfigNestedValueType::Uint32
| ConfigNestedValueType::Uint64 => "Uint",
ConfigNestedValueType::Int8
| ConfigNestedValueType::Int16
| ConfigNestedValueType::Int32
| ConfigNestedValueType::Int64 => "Int",
ConfigNestedValueType::String { .. } => "String",
},
});
/// Trait for unwrapping results with Display errors so we can see template syntax errors correctly.
trait ResultExt<T> {
fn pretty_unwrap(self) -> T;
}
impl<T, E> ResultExt<T> for Result<T, E>
where
E: std::fmt::Display,
{
fn pretty_unwrap(self) -> T {
match self {
Ok(t) => t,
Err(e) => panic!("unwrap failed: {}", e),
}
}
}