use std::collections::BTreeSet;
use std::fmt::Write as _;
use type_bridge_contract::codec::to_canonical_json;
use type_bridge_contract::diagnostic::Diagnostic;
use type_bridge_contract::fingerprint::{CanonicalizationVersion, Fingerprint, FingerprintDomain};
use type_bridge_contract::id::TypeKind;
use type_bridge_contract::projection::{
ModelProjection, ProjectedContainer, ProjectedTokenIdentity, ProjectedTokenKind,
ProjectedTypeRef, RoleTokenProjection, RuntimeProjection, TYPE_BRIDGE_C_ABI_MAJOR,
TYPE_BRIDGE_C_CREATE_FIELD_MAX, TYPE_BRIDGE_C_CREATE_MEMBER_MAX, TYPE_BRIDGE_C_CREATE_ROLE_MAX,
TYPE_BRIDGE_PROJECTED_TOKEN_VERSION, TargetIdentifier,
};
use type_bridge_contract::schema::OwnsFactId;
use type_bridge_contract::value::ValueTypeTag;
use crate::{EmbeddedAuthority, GeneratedPackage, invalid, projection_uses_ordered_collections};
mod query;
const TEMPLATE_PREFIX: &str = "@TYPE_BRIDGE_C_SYMBOL_PREFIX@";
const C_MAX_TARGET_IDENTIFIER_BYTES: usize = 255;
const C_TRANSLATION_UNIT_IDENTIFIER_MAX: usize = 4_095;
const C_SIMULTANEOUS_MACRO_MAX: usize = 4_095;
const C_HOSTED_OBJECT_BYTES_MIN: usize = 65_535;
const C_EMBEDDED_BYTE_CHUNK_MAX: usize = 32_768;
const C_CREATE_ARGS_VERSION: u32 = 1;
const C_RUNTIME_HEADER_EXTERNAL_IDENTIFIER_COUNT: usize = 340;
const C_RUNTIME_HEADER_MACRO_IDENTIFIER_COUNT: usize = 262;
const C_SUPPORTED_IMPLEMENTATION_MACRO_RESERVE: usize = 2_048;
const C_GENERATED_SYMBOL_DOMAIN: &str = "typebridge.generator.c-symbol";
const C_GENERATED_SYMBOL_CANONICALIZATION: &str = "typebridge.c-generated-symbol/v2";
pub(super) fn render(
projection: &RuntimeProjection,
authority: &EmbeddedAuthority,
cmake_template: &[u8],
cmake_package_config_template: &[u8],
pkg_config_template: &[u8],
) -> Result<GeneratedPackage, Diagnostic> {
let ordered = projection_uses_ordered_collections(projection);
let prefix = projection
.config()
.c_symbol_prefix()
.ok_or_else(|| {
invalid(
"c_emitter_missing_symbol_prefix",
"C projection has no symbol prefix",
)
})?
.as_str();
let header_path = format!("include/{prefix}/models.h");
let pkg_config_path = format!("{prefix}.pc.in");
let cmake_package_config_path = format!("{prefix}Config.cmake.in");
let cmake = render_template(cmake_template, prefix, "c_emitter_invalid_cmake_template")?;
let cmake_package_config = render_template(
cmake_package_config_template,
prefix,
"c_emitter_invalid_cmake_package_config_template",
)?;
let pkg_config = render_template(
pkg_config_template,
prefix,
"c_emitter_invalid_pkg_config_template",
)?;
let projection_json = to_canonical_json(projection)?;
let semantic_json = to_canonical_json(projection.semantic_fingerprint())?;
let binding_json = to_canonical_json(projection.projection_fingerprint())?;
validate_c_projection_limits(projection, prefix, ordered)?;
GeneratedPackage::try_new([
("CMakeLists.txt".to_owned(), cmake.into_bytes()),
(cmake_package_config_path, cmake_package_config.into_bytes()),
(
header_path,
render_header(projection, prefix, ordered)?.into_bytes(),
),
(
"src/models.c".to_owned(),
render_source(
projection,
prefix,
authority,
&projection_json,
&semantic_json,
&binding_json,
ordered,
)?
.into_bytes(),
),
(pkg_config_path, pkg_config.into_bytes()),
])
}
fn render_template(bytes: &[u8], prefix: &str, code: &'static str) -> Result<String, Diagnostic> {
let template = std::str::from_utf8(bytes)
.map_err(|_| invalid(code, "fixed C package template must be UTF-8"))?;
if !template.contains(TEMPLATE_PREFIX) {
return Err(invalid(
code,
"fixed C package template is missing its symbol-prefix placeholder",
));
}
Ok(template.replace(TEMPLATE_PREFIX, prefix))
}
fn render_header(
projection: &RuntimeProjection,
prefix: &str,
ordered: bool,
) -> Result<String, Diagnostic> {
validate_generated_symbols(projection, prefix, ordered)?;
let guard = format!("{}_TYPE_BRIDGE_MODELS_H", prefix.to_ascii_uppercase());
let macro_prefix = prefix.to_ascii_uppercase();
let mut output = format!(
"/* Generated by type-bridge from a verified C RuntimeProjection. Do not edit. */\n\
#ifndef {guard}\n#define {guard}\n\n\
#include <typebridge/type_bridge.h>\n\n\
#define {macro_prefix}_CREATE_ARGS_VERSION {C_CREATE_ARGS_VERSION}u\n\
#define {macro_prefix}_CREATE_FIELD_MAX {TYPE_BRIDGE_C_CREATE_FIELD_MAX}u\n\
#define {macro_prefix}_CREATE_ROLE_MAX {TYPE_BRIDGE_C_CREATE_ROLE_MAX}u\n\
#define {macro_prefix}_CREATE_MEMBER_MAX {TYPE_BRIDGE_C_CREATE_MEMBER_MAX}u\n\
#define {macro_prefix}_TRANSLATION_UNIT_IDENTIFIER_MAX {C_TRANSLATION_UNIT_IDENTIFIER_MAX}u\n\
#define {macro_prefix}_SIMULTANEOUS_MACRO_MAX {C_SIMULTANEOUS_MACRO_MAX}u\n\
#define {macro_prefix}_IMPLEMENTATION_MACRO_RESERVE {C_SUPPORTED_IMPLEMENTATION_MACRO_RESERVE}u\n\
#define {macro_prefix}_HOSTED_OBJECT_BYTES_MIN {C_HOSTED_OBJECT_BYTES_MIN}u\n\n\
#define {macro_prefix}_EMBEDDED_BYTE_CHUNK_MAX {C_EMBEDDED_BYTE_CHUNK_MAX}u\n\
#define {macro_prefix}_SEQUENCE_OBJECT_BYTES_MAX {C_HOSTED_OBJECT_BYTES_MIN}u\n\n\
#if defined(__cplusplus)\n\
static_assert(TYPE_BRIDGE_PROJECTED_CREATE_BUILDER_CHUNK_LEN_MAX <=\n\
{macro_prefix}_HOSTED_OBJECT_BYTES_MIN /\n\
sizeof(const type_bridge_projected_value_t *),\n\
\"generated value scratch exceeds the C hosted-object minimum\");\n\
static_assert(TYPE_BRIDGE_PROJECTED_CREATE_BUILDER_CHUNK_LEN_MAX <=\n\
{macro_prefix}_HOSTED_OBJECT_BYTES_MIN /\n\
sizeof(const type_bridge_projected_reference_t *),\n\
\"generated reference scratch exceeds the C hosted-object minimum\");\n\
#else\n\
_Static_assert(TYPE_BRIDGE_PROJECTED_CREATE_BUILDER_CHUNK_LEN_MAX <=\n\
{macro_prefix}_HOSTED_OBJECT_BYTES_MIN /\n\
sizeof(const type_bridge_projected_value_t *),\n\
\"generated value scratch exceeds the C hosted-object minimum\");\n\
_Static_assert(TYPE_BRIDGE_PROJECTED_CREATE_BUILDER_CHUNK_LEN_MAX <=\n\
{macro_prefix}_HOSTED_OBJECT_BYTES_MIN /\n\
sizeof(const type_bridge_projected_reference_t *),\n\
\"generated reference scratch exceeds the C hosted-object minimum\");\n\
#endif\n\n\
#ifdef __cplusplus\nextern \"C\" {{\n#endif\n\n"
);
for name in projected_nominal_names(projection, ordered)? {
let _ = writeln!(output, "typedef struct {name} {name};");
}
render_projected_token_declarations(&mut output, projection, prefix, ordered);
render_attribute_declarations(&mut output, projection, prefix)?;
render_role_union_declarations(&mut output, projection, prefix)?;
render_entity_model_declarations(&mut output, projection, prefix)?;
render_relation_model_declarations(&mut output, projection, prefix)?;
if ordered {
render_canonical_codec_declarations(&mut output, projection)?;
}
render_generated_helpers(&mut output, prefix)?;
if ordered {
render_successor_model_api(&mut output, projection, prefix)?;
}
query::render_inline(&mut output, projection, prefix, ordered)?;
if ordered {
let _ = write!(
output,
"\n#define {macro_prefix}_MIGRATION_HISTORY_RESOURCE \"typebridge/migration-history.json\"\n\n\
type_bridge_status_t TYPE_BRIDGE_CALL {prefix}_schema_package_open(\n\
type_bridge_schema_package_t **out_package,\n\
type_bridge_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {prefix}_schema_package_open_v2(\n\
type_bridge_schema_package_t **out_package,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\n\
type_bridge_status_t TYPE_BRIDGE_CALL {prefix}_migration_catalog_open(\n\
type_bridge_byte_view_t history_bundle,\n\
type_bridge_migration_catalog_t **out_catalog,\n\
type_bridge_diagnostics_t **out_diagnostics);\n\n\
#ifdef __cplusplus\n}}\n#endif\n\n#endif /* {guard} */\n"
);
} else {
let _ = write!(
output,
"\ntype_bridge_status_t TYPE_BRIDGE_CALL {prefix}_schema_package_open(\n\
type_bridge_schema_package_t **out_package,\n\
type_bridge_diagnostics_t **out_diagnostics);\n\n\
#ifdef __cplusplus\n}}\n#endif\n\n#endif /* {guard} */\n"
);
}
Ok(output)
}
fn projected_nominal_names(
projection: &RuntimeProjection,
ordered: bool,
) -> Result<BTreeSet<String>, Diagnostic> {
let mut names = BTreeSet::new();
let mut insert = |name: &str| {
if !names.insert(name.to_owned()) {
return Err(invalid(
"c_emitter_duplicate_nominal_identifier",
"C projection repeats one nominal identifier",
));
}
Ok(())
};
for model in projection.models().values() {
insert(model.target_name().as_str())?;
if let Some(name) = model.create().target_name() {
insert(name.as_str())?;
}
if let Some(name) = model.reference_read().target_name() {
insert(name.as_str())?;
}
if let Some(name) = model.query_tokens().target_name() {
insert(name.as_str())?;
}
for role in model.query_tokens().roles().values() {
if let Some(name) = role.player_union_target_name() {
insert(name.as_str())?;
}
}
}
for structure in projection.structs().values() {
insert(structure.target_name().as_str())?;
}
for function in projection.functions().values() {
insert(function.target_name().as_str())?;
}
for playing in projection.playing_facts().values() {
if let Some(name) = playing.target_name() {
insert(name.as_str())?;
}
}
let prefix = projection
.config()
.c_symbol_prefix()
.expect("C renderer validated its symbol prefix")
.as_str();
for name in query::nominal_names(projection, prefix, ordered)? {
insert(&name)?;
}
if ordered {
for model in projection.models().values() {
for operation in successor_batch_operations(model) {
for name in successor_batch_type_names(model, operation)? {
insert(&name)?;
}
}
}
}
Ok(names)
}
fn render_source(
projection: &RuntimeProjection,
prefix: &str,
authority: &EmbeddedAuthority,
projection_json: &[u8],
semantic_json: &[u8],
binding_json: &[u8],
ordered: bool,
) -> Result<String, Diagnostic> {
validate_embedded_resource_symbols(
projection,
prefix,
ordered,
&[
(
"schema_authority_json",
authority.canonical_envelope_json.len(),
),
("declared_schema_json", authority.declared_schema_json.len()),
("runtime_projection_json", projection_json.len()),
("semantic_fingerprint_json", semantic_json.len()),
("binding_fingerprint_json", binding_json.len()),
("managed_scope", authority.managed_scope_id.len()),
("semantic_profile", authority.semantic_profile_id.len()),
],
)?;
let mut output = format!(
"/* Generated by type-bridge from verified canonical evidence. Do not edit. */\n\
#include <{prefix}/models.h>\n\n"
);
render_projected_token_definitions(&mut output, projection, prefix, ordered);
render_attribute_definitions(&mut output, projection, prefix)?;
render_role_union_definitions(&mut output, projection, prefix)?;
render_entity_model_definitions(&mut output, projection, prefix)?;
render_relation_model_definitions(&mut output, projection, prefix)?;
if ordered {
render_canonical_codec_definitions(&mut output, projection, prefix)?;
}
render_chunked_byte_view(
&mut output,
&format!("{prefix}_schema_authority_json"),
authority.canonical_envelope_json.as_bytes(),
);
render_chunked_byte_view(
&mut output,
&format!("{prefix}_declared_schema_json"),
authority.declared_schema_json.as_bytes(),
);
render_chunked_byte_view(
&mut output,
&format!("{prefix}_runtime_projection_json"),
projection_json,
);
render_chunked_byte_view(
&mut output,
&format!("{prefix}_semantic_fingerprint_json"),
semantic_json,
);
render_chunked_byte_view(
&mut output,
&format!("{prefix}_binding_fingerprint_json"),
binding_json,
);
render_chunked_byte_view(
&mut output,
&format!("{prefix}_managed_scope"),
authority.managed_scope_id.as_bytes(),
);
render_chunked_byte_view(
&mut output,
&format!("{prefix}_semantic_profile"),
authority.semantic_profile_id.as_bytes(),
);
let descriptor_abi_minor = type_bridge_contract::projection::TYPE_BRIDGE_C_ABI_MINOR;
let _ = write!(
output,
"static const type_bridge_schema_package_chunked_descriptor_v1_t\n\
{prefix}_schema_package_chunks_v1 = {{\n\
\x20 sizeof(type_bridge_schema_package_chunked_descriptor_v1_t),\n\
\x20 {TYPE_BRIDGE_C_ABI_MAJOR}u,\n\
\x20 {descriptor_abi_minor}u,\n\
\x20 0u,\n\
\x20 {schema_authority},\n\
\x20 {declared_schema},\n\
\x20 {runtime_projection},\n\
\x20 {semantic_fingerprint},\n\
\x20 {binding_fingerprint},\n\
\x20 {managed_scope},\n\
\x20 {semantic_profile},\n\
\x20 {{ 0u, 0u, 0u, 0u }}\n\
}};\n\
_Static_assert(sizeof({prefix}_schema_package_chunks_v1) <=\n\
{macro_prefix}_HOSTED_OBJECT_BYTES_MIN,\n\
\"generated package descriptor exceeds the C hosted-object minimum\");\n\n\
type_bridge_status_t TYPE_BRIDGE_CALL {prefix}_schema_package_open(\n\
type_bridge_schema_package_t **out_package,\n\
type_bridge_diagnostics_t **out_diagnostics) {{\n\
return type_bridge_schema_package_open_chunked_v1(\n\
&{prefix}_schema_package_chunks_v1, out_package, out_diagnostics);\n\
}}\n",
macro_prefix = prefix.to_ascii_uppercase(),
schema_authority = chunked_byte_view_initializer(
&format!("{prefix}_schema_authority_json"),
authority.canonical_envelope_json.len(),
),
declared_schema = chunked_byte_view_initializer(
&format!("{prefix}_declared_schema_json"),
authority.declared_schema_json.len(),
),
runtime_projection = chunked_byte_view_initializer(
&format!("{prefix}_runtime_projection_json"),
projection_json.len(),
),
semantic_fingerprint = chunked_byte_view_initializer(
&format!("{prefix}_semantic_fingerprint_json"),
semantic_json.len(),
),
binding_fingerprint = chunked_byte_view_initializer(
&format!("{prefix}_binding_fingerprint_json"),
binding_json.len(),
),
managed_scope = chunked_byte_view_initializer(
&format!("{prefix}_managed_scope"),
authority.managed_scope_id.len(),
),
semantic_profile = chunked_byte_view_initializer(
&format!("{prefix}_semantic_profile"),
authority.semantic_profile_id.len(),
),
);
if ordered {
let [add_alias_input, alias_preflight] = generated_alias_helper_symbols(prefix)?;
let _ = write!(
output,
"\n\
type_bridge_status_t TYPE_BRIDGE_CALL {prefix}_schema_package_open_v2(\n\
type_bridge_schema_package_t **out_package,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
return type_bridge_schema_package_open_chunked_v2(\n\
&{prefix}_schema_package_chunks_v1, out_package, out_diagnostics);\n\
}}\n"
);
let _ = write!(
output,
"\n\
type_bridge_status_t TYPE_BRIDGE_CALL {prefix}_migration_catalog_open(\n\
type_bridge_byte_view_t history_bundle,\n\
type_bridge_migration_catalog_t **out_catalog,\n\
type_bridge_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[1];\n\
size_t alias_input_count = 0u;\n\
type_bridge_schema_package_t *package = NULL;\n\
type_bridge_status_t status;\n\
if (out_catalog == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
{add_alias_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, history_bundle.data,\n\
history_bundle.length);\n\
status = {alias_preflight}(alias_inputs, alias_input_count,\n\
out_catalog, sizeof(*out_catalog),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
*out_catalog = NULL;\n\
*out_diagnostics = NULL;\n\
status = {prefix}_schema_package_open(\n\
&package, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{\n\
return status;\n\
}}\n\
status = type_bridge_migration_catalog_open(\n\
package, history_bundle, out_catalog, out_diagnostics);\n\
type_bridge_status_t close_status =\n\
type_bridge_schema_package_close(&package);\n\
return status == TYPE_BRIDGE_STATUS_OK ? close_status : status;\n\
}}\n"
);
}
Ok(output)
}
fn projected_token_kinds(ordered: bool) -> Vec<(ProjectedTokenKind, &'static str)> {
let mut kinds = vec![
(ProjectedTokenKind::Model, "model"),
(ProjectedTokenKind::Field, "field"),
(ProjectedTokenKind::Role, "role"),
(ProjectedTokenKind::Function, "function"),
];
if ordered {
kinds.extend([
(ProjectedTokenKind::Struct, "struct"),
(ProjectedTokenKind::Attribute, "attribute"),
]);
}
kinds
}
fn generated_alias_helper_symbols(prefix: &str) -> Result<[String; 2], Diagnostic> {
Ok([
generated_symbol(prefix, "generated_alias_input_v1")?,
generated_symbol(prefix, "generated_alias_preflight_v1")?,
])
}
fn render_generated_helpers(output: &mut String, prefix: &str) -> Result<(), Diagnostic> {
let [add_input, preflight] = generated_alias_helper_symbols(prefix)?;
let _ = write!(
output,
"static inline void {add_input}(\n\
type_bridge_generated_opaque_input_v1_t *inputs,\n\
size_t *input_count,\n\
type_bridge_generated_opaque_input_kind_t kind,\n\
const void *pointer, size_t count) {{\n\
type_bridge_generated_opaque_input_v1_t *input;\n\
if (pointer == NULL || count == 0u) {{ return; }}\n\
input = &inputs[*input_count];\n\
input->struct_size = sizeof(type_bridge_generated_opaque_input_v1_t);\n\
input->version = TYPE_BRIDGE_GENERATED_ALIAS_PREFLIGHT_VERSION;\n\
input->kind = kind;\n\
input->reserved0 = 0u;\n\
input->pointer = pointer;\n\
input->count = count;\n\
input->reserved[0] = 0u;\n\
input->reserved[1] = 0u;\n\
input->reserved[2] = 0u;\n\
input->reserved[3] = 0u;\n\
++*input_count;\n\
}}\n\n\
static inline type_bridge_status_t {preflight}(\n\
const type_bridge_generated_opaque_input_v1_t *inputs,\n\
size_t input_count,\n\
void *first_output, size_t first_output_length,\n\
void *second_output, size_t second_output_length) {{\n\
type_bridge_generated_output_range_v1_t outputs[2];\n\
size_t output_count = 0u;\n\
if (first_output != NULL) {{\n\
outputs[output_count].struct_size = sizeof(type_bridge_generated_output_range_v1_t);\n\
outputs[output_count].version = TYPE_BRIDGE_GENERATED_ALIAS_PREFLIGHT_VERSION;\n\
outputs[output_count].pointer = first_output;\n\
outputs[output_count].length = first_output_length;\n\
outputs[output_count].reserved[0] = 0u;\n\
outputs[output_count].reserved[1] = 0u;\n\
outputs[output_count].reserved[2] = 0u;\n\
outputs[output_count].reserved[3] = 0u;\n\
++output_count;\n\
}}\n\
if (second_output != NULL) {{\n\
outputs[output_count].struct_size = sizeof(type_bridge_generated_output_range_v1_t);\n\
outputs[output_count].version = TYPE_BRIDGE_GENERATED_ALIAS_PREFLIGHT_VERSION;\n\
outputs[output_count].pointer = second_output;\n\
outputs[output_count].length = second_output_length;\n\
outputs[output_count].reserved[0] = 0u;\n\
outputs[output_count].reserved[1] = 0u;\n\
outputs[output_count].reserved[2] = 0u;\n\
outputs[output_count].reserved[3] = 0u;\n\
++output_count;\n\
}}\n\
if (output_count == 0u) {{ return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT; }}\n\
return type_bridge_generated_opaque_alias_preflight_v1(\n\
input_count == 0u ? NULL : inputs, input_count,\n\
outputs, output_count);\n\
}}\n\n"
);
Ok(())
}
fn projected_tokens(
projection: &RuntimeProjection,
ordered: bool,
) -> Vec<(ProjectedTokenKind, &'static str, u32)> {
let mut tokens = Vec::new();
for (kind, kind_name) in projected_token_kinds(ordered) {
let mut ordinal = 0_u32;
while projection.projected_token_identity(kind, ordinal).is_some() {
tokens.push((kind, kind_name, ordinal));
ordinal = ordinal
.checked_add(1)
.expect("projected token count is bounded below u32::MAX");
}
}
tokens
}
fn projected_token_symbol(prefix: &str, kind_name: &str, ordinal: u32) -> String {
format!("{prefix}_projected_{kind_name}_token_{ordinal}")
}
fn render_projected_token_declarations(
output: &mut String,
projection: &RuntimeProjection,
prefix: &str,
ordered: bool,
) {
if !projection.models().is_empty() {
output.push_str(
"\n/* Generated-only schema tokens. Pass their addresses only through generated APIs. */\n",
);
}
for (_, kind_name, ordinal) in projected_tokens(projection, ordered) {
let symbol = projected_token_symbol(prefix, kind_name, ordinal);
let _ = writeln!(
output,
"extern const type_bridge_projected_token_v1_t {symbol};"
);
}
}
fn render_projected_token_definitions(
output: &mut String,
projection: &RuntimeProjection,
prefix: &str,
ordered: bool,
) {
let digest = projection
.projection_fingerprint()
.as_fingerprint()
.digest()
.bytes();
for (kind, kind_name, ordinal) in projected_tokens(projection, ordered) {
let symbol = projected_token_symbol(prefix, kind_name, ordinal);
let _ = writeln!(
output,
"const type_bridge_projected_token_v1_t {symbol} = {{"
);
let _ = writeln!(
output,
" sizeof(type_bridge_projected_token_v1_t),\n {TYPE_BRIDGE_PROJECTED_TOKEN_VERSION}u,\n {}u,\n {ordinal}u,",
kind.as_u32()
);
output.push_str(" { ");
for byte in digest {
let _ = write!(output, "0x{byte:02x}u, ");
}
output.push_str("},\n { 0u, 0u, 0u, 0u }\n};\n\n");
}
}
#[derive(Clone, Copy)]
struct AttributeAbi {
input_type: &'static str,
open_function: &'static str,
output_type: &'static str,
value_function: &'static str,
}
fn attribute_abi(value_type: ValueTypeTag) -> AttributeAbi {
match value_type {
ValueTypeTag::String => AttributeAbi {
input_type: "type_bridge_byte_view_t",
open_function: "type_bridge_projected_value_string_open",
output_type: "type_bridge_byte_view_t",
value_function: "type_bridge_projected_value_text",
},
ValueTypeTag::Long => AttributeAbi {
input_type: "int64_t",
open_function: "type_bridge_projected_value_long_open",
output_type: "int64_t",
value_function: "type_bridge_projected_value_long",
},
ValueTypeTag::Double => AttributeAbi {
input_type: "uint64_t",
open_function: "type_bridge_projected_value_double_open",
output_type: "uint64_t",
value_function: "type_bridge_projected_value_double_bits",
},
ValueTypeTag::Boolean => AttributeAbi {
input_type: "uint8_t",
open_function: "type_bridge_projected_value_boolean_open",
output_type: "uint8_t",
value_function: "type_bridge_projected_value_boolean",
},
ValueTypeTag::Date => lexical_attribute_abi("type_bridge_projected_value_date_open"),
ValueTypeTag::DateTime => {
lexical_attribute_abi("type_bridge_projected_value_datetime_open")
}
ValueTypeTag::DateTimeTz => {
lexical_attribute_abi("type_bridge_projected_value_datetime_tz_open")
}
ValueTypeTag::Decimal => lexical_attribute_abi("type_bridge_projected_value_decimal_open"),
ValueTypeTag::Duration => {
lexical_attribute_abi("type_bridge_projected_value_duration_open")
}
}
}
const fn lexical_attribute_abi(open_function: &'static str) -> AttributeAbi {
AttributeAbi {
input_type: "type_bridge_byte_view_t",
open_function,
output_type: "type_bridge_byte_view_t",
value_function: "type_bridge_projected_value_text",
}
}
fn bounded_generated_identifier(unbounded: &str) -> Result<String, Diagnostic> {
if TargetIdentifier::c(unbounded).is_ok() {
return Ok(unbounded.to_owned());
}
let digest = Fingerprint::compute(
FingerprintDomain::new(C_GENERATED_SYMBOL_DOMAIN)?,
CanonicalizationVersion::new(C_GENERATED_SYMBOL_CANONICALIZATION)?,
None,
unbounded.as_bytes(),
)
.digest()
.to_hex();
let mut stem_bytes = C_MAX_TARGET_IDENTIFIER_BYTES - digest.len() - 1;
while unbounded.as_bytes().get(stem_bytes - 1) == Some(&b'_') {
stem_bytes -= 1;
}
let bounded = format!("{}_{}", &unbounded[..stem_bytes], digest);
TargetIdentifier::c(bounded.clone())?;
Ok(bounded)
}
fn generated_symbol(base: &str, suffix: &str) -> Result<String, Diagnostic> {
bounded_generated_identifier(&format!("{base}_{suffix}"))
}
pub(super) fn bound_long_generated_identifiers(source: &str) -> Result<String, Diagnostic> {
let mut output = String::with_capacity(source.len());
let mut start = 0;
let bytes = source.as_bytes();
while start < bytes.len() {
let byte = bytes[start];
if byte.is_ascii_alphabetic() || byte == b'_' {
let mut end = start + 1;
while end < bytes.len() && (bytes[end].is_ascii_alphanumeric() || bytes[end] == b'_') {
end += 1;
}
let identifier = &source[start..end];
if identifier.len() > C_MAX_TARGET_IDENTIFIER_BYTES {
output.push_str(&bounded_generated_identifier(identifier)?);
} else {
output.push_str(identifier);
}
start = end;
} else {
output.push(byte as char);
start += 1;
}
}
Ok(output)
}
fn model_token_symbol(
projection: &RuntimeProjection,
prefix: &str,
model: &type_bridge_contract::id::TypeId,
) -> Result<String, Diagnostic> {
let ordinal = projection
.projected_token_ordinal(&ProjectedTokenIdentity::Model(model.clone()))
.ok_or_else(|| {
invalid(
"c_emitter_missing_model_token",
"projected C model has no deterministic model-token ordinal",
)
})?;
Ok(projected_token_symbol(prefix, "model", ordinal))
}
fn attribute_symbols(base: &str) -> Result<[String; 3], Diagnostic> {
Ok([
generated_symbol(base, "open")?,
generated_symbol(base, "value")?,
generated_symbol(base, "close")?,
])
}
struct RoleUnionVariantSymbols<'a> {
model: &'a ModelProjection,
model_token: String,
model_ordinal: u32,
kind_constant: String,
from_reference: String,
as_reference: String,
}
struct RoleUnionSymbols<'a> {
target: &'a str,
role_token: String,
kind_type: String,
kind_unknown: String,
kind_function: String,
close: String,
variants: Vec<RoleUnionVariantSymbols<'a>>,
}
fn model_token_ordinal(
projection: &RuntimeProjection,
model: &type_bridge_contract::id::TypeId,
) -> Result<u32, Diagnostic> {
projection
.projected_token_ordinal(&ProjectedTokenIdentity::Model(model.clone()))
.ok_or_else(|| {
invalid(
"c_emitter_missing_model_token",
"projected C model has no deterministic model-token ordinal",
)
})
}
fn role_token_symbol(
projection: &RuntimeProjection,
prefix: &str,
owner: &type_bridge_contract::id::TypeId,
role: &type_bridge_contract::id::RoleId,
) -> Result<String, Diagnostic> {
let ordinal = projection
.projected_token_ordinal(&ProjectedTokenIdentity::Role {
owner: owner.clone(),
role: role.clone(),
})
.ok_or_else(|| {
invalid(
"c_emitter_missing_role_token",
"projected C relation role has no deterministic role-token ordinal",
)
})?;
Ok(projected_token_symbol(prefix, "role", ordinal))
}
fn function_token_symbol(
projection: &RuntimeProjection,
prefix: &str,
function: &type_bridge_contract::id::FunctionId,
) -> Result<String, Diagnostic> {
let ordinal = projection
.projected_token_ordinal(&ProjectedTokenIdentity::Function(function.clone()))
.ok_or_else(|| {
invalid(
"c_emitter_missing_function_token",
"projected C function has no deterministic function-token ordinal",
)
})?;
Ok(projected_token_symbol(prefix, "function", ordinal))
}
fn attribute_token_symbol(
projection: &RuntimeProjection,
prefix: &str,
attribute: &type_bridge_contract::id::AttributeId,
) -> Result<String, Diagnostic> {
let ordinal = projection
.projected_token_ordinal(&ProjectedTokenIdentity::Attribute(attribute.clone()))
.ok_or_else(|| {
invalid(
"c_emitter_missing_attribute_token",
"projected C attribute has no deterministic attribute-token ordinal",
)
})?;
Ok(projected_token_symbol(prefix, "attribute", ordinal))
}
fn struct_token_symbol(
projection: &RuntimeProjection,
prefix: &str,
structure: &type_bridge_contract::id::StructId,
) -> Result<String, Diagnostic> {
let ordinal = projection
.projected_token_ordinal(&ProjectedTokenIdentity::Struct(structure.clone()))
.ok_or_else(|| {
invalid(
"c_emitter_missing_struct_token",
"projected C struct has no deterministic struct-token ordinal",
)
})?;
Ok(projected_token_symbol(prefix, "struct", ordinal))
}
fn role_union_symbols<'a>(
projection: &'a RuntimeProjection,
role: &'a RoleTokenProjection,
prefix: &str,
) -> Result<RoleUnionSymbols<'a>, Diagnostic> {
let target = role
.player_union_target_name()
.ok_or_else(|| {
invalid(
"c_emitter_role_union_missing",
"projected C relation role has no nominal player-union name",
)
})?
.as_str();
let mut variants = Vec::with_capacity(role.accepted_players().len());
for player in role.accepted_players() {
let model = projection.models().get(player).ok_or_else(|| {
invalid(
"c_emitter_role_player_missing",
"projected C relation role references an absent player model",
)
})?;
if !matches!(player.kind(), TypeKind::Entity | TypeKind::Relation)
|| model.reference_read().target_name().is_none()
{
return Err(invalid(
"c_emitter_role_player_reference_missing",
"projected C role players must expose nominal reference models",
));
}
let member = projected_member_suffix(prefix, model.target_name())?;
variants.push(RoleUnionVariantSymbols {
model,
model_token: model_token_symbol(projection, prefix, player)?,
model_ordinal: model_token_ordinal(projection, player)?,
kind_constant: generated_symbol(target, &format!("kind_{member}"))?,
from_reference: generated_symbol(target, &format!("from_{member}"))?,
as_reference: generated_symbol(target, &format!("as_{member}"))?,
});
}
Ok(RoleUnionSymbols {
target,
role_token: role_token_symbol(projection, prefix, role.owner(), role.role())?,
kind_type: generated_symbol(target, "kind_t")?,
kind_unknown: generated_symbol(target, "kind_unknown")?,
kind_function: generated_symbol(target, "kind")?,
close: generated_symbol(target, "close")?,
variants,
})
}
fn render_role_union_declarations(
output: &mut String,
projection: &RuntimeProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Relation)
{
for role in model.query_tokens().roles().values() {
let symbols = role_union_symbols(projection, role, prefix)?;
let _ = writeln!(
output,
"\n/* Closed owned role-player union `{}`. */",
symbols.target
);
let _ = writeln!(output, "typedef uint32_t {};", symbols.kind_type);
let _ = writeln!(output, "#define {} UINT32_C(0)", symbols.kind_unknown);
for (index, variant) in symbols.variants.iter().enumerate() {
let _ = writeln!(
output,
"#define {} UINT32_C({})",
variant.kind_constant,
index + 1
);
}
for variant in &symbols.variants {
let reference = variant
.model
.reference_read()
.target_name()
.expect("role-player reference target was validated");
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {}(\n\
const {} *reference,\n\
{} **out_player,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {}(\n\
const {} *player,\n\
{} **out_reference,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
variant.from_reference,
reference.as_str(),
symbols.target,
variant.as_reference,
symbols.target,
reference.as_str(),
);
}
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {}(\n\
const {} *player, {} *out_kind,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {}({} **player);\n",
symbols.kind_function,
symbols.target,
symbols.kind_type,
symbols.close,
symbols.target,
);
}
}
Ok(())
}
fn render_role_union_definitions(
output: &mut String,
projection: &RuntimeProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
let [add_input, preflight] = generated_alias_helper_symbols(prefix)?;
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Relation)
{
for role in model.query_tokens().roles().values() {
let symbols = role_union_symbols(projection, role, prefix)?;
for variant in &symbols.variants {
let reference = variant
.model
.reference_read()
.target_name()
.expect("role-player reference target was validated")
.as_str();
for (function, input_type, input_name, output_type, output_name) in [
(
variant.from_reference.as_str(),
reference,
"reference",
symbols.target,
"out_player",
),
(
variant.as_reference.as_str(),
symbols.target,
"player",
reference,
"out_reference",
),
] {
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {function}(\n\
const {input_type} *{input_name},\n\
{output_type} **{output_name},\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_reference_t *generic_reference = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[3];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_REFERENCE,\n\
{input_name}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN,\n\
&{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN,\n\
&{role_token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
{output_name}, sizeof(*{output_name}),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if ({output_name} != NULL) {{ *{output_name} = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if ({output_name} == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_reference_validate_role(\n\
(const type_bridge_projected_reference_t *){input_name},\n\
&{role_token}, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
status = type_bridge_projected_reference_validate_model(\n\
(const type_bridge_projected_reference_t *){input_name},\n\
&{model_token}, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
status = type_bridge_projected_reference_clone(\n\
(const type_bridge_projected_reference_t *){input_name},\n\
&generic_reference, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*{output_name} = ({output_type} *)generic_reference;\n\
}}\n\
return status;\n\
}}\n\n",
model_token = variant.model_token,
role_token = symbols.role_token,
);
}
}
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {kind_function}(\n\
const {target} *player, {kind_type} *out_kind,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[1];\n\
size_t alias_input_count = 0u;\n\
uint32_t ordinal = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_REFERENCE, player, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_kind, sizeof(*out_kind),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n",
kind_function = symbols.kind_function,
target = symbols.target,
kind_type = symbols.kind_type,
);
let _ = write!(
output,
" alias_input_count = 0u;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN,\n\
&{}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_kind, sizeof(*out_kind),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n",
symbols.role_token,
);
for variant in &symbols.variants {
let _ = write!(
output,
" alias_input_count = 0u;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN,\n\
&{}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_kind, sizeof(*out_kind),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n",
variant.model_token,
);
}
let _ = write!(
output,
" if (out_kind != NULL) {{ *out_kind = {kind_unknown}; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_kind == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_reference_validate_role(\n\
(const type_bridge_projected_reference_t *)player,\n\
&{role_token}, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
status = type_bridge_projected_reference_model_ordinal(\n\
(const type_bridge_projected_reference_t *)player,\n\
&ordinal, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n",
kind_unknown = symbols.kind_unknown,
role_token = symbols.role_token,
);
for variant in &symbols.variants {
let _ = write!(
output,
" if (ordinal == {}u) {{\n\
status = type_bridge_projected_reference_validate_model(\n\
(const type_bridge_projected_reference_t *)player,\n\
&{}, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_kind = {};\n\
}}\n\
return status;\n\
}}\n",
variant.model_ordinal, variant.model_token, variant.kind_constant,
);
}
if let Some(first) = symbols.variants.first() {
let _ = write!(
output,
" return type_bridge_projected_reference_validate_model(\n\
(const type_bridge_projected_reference_t *)player,\n\
&{}, out_diagnostics);\n",
first.model_token,
);
} else {
output.push_str(" return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n");
}
let _ = write!(
output,
"}}\n\n\
type_bridge_status_t TYPE_BRIDGE_CALL {}({} **player) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[1];\n\
size_t alias_input_count = 0u;\n\
type_bridge_projected_reference_t *generic_reference;\n\
type_bridge_status_t status;\n\
if (player == NULL) {{ return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT; }}\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_REFERENCE, *player, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
player, sizeof(*player), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
generic_reference = (type_bridge_projected_reference_t *)*player;\n\
status = type_bridge_projected_reference_close(&generic_reference);\n\
*player = ({} *)generic_reference;\n\
return status;\n\
}}\n\n",
symbols.close, symbols.target, symbols.target,
);
}
}
Ok(())
}
fn validate_generated_symbols(
projection: &RuntimeProjection,
prefix: &str,
ordered: bool,
) -> Result<BTreeSet<String>, Diagnostic> {
let mut symbols = projected_nominal_names(projection, ordered)?;
let mut insert = |symbol: String| {
if !symbols.insert(symbol) {
return Err(invalid(
"c_emitter_generated_symbol_collision",
"generated C API symbols collide in the global identifier namespace",
));
}
Ok(())
};
insert(format!("{prefix}_schema_package_open"))?;
if ordered {
insert(format!("{prefix}_schema_package_open_v2"))?;
insert(format!("{prefix}_migration_catalog_open"))?;
}
for symbol in query::auxiliary_type_names(projection, prefix, ordered)? {
insert(symbol)?;
}
for symbol in query::function_names(projection, prefix, ordered)? {
insert(symbol)?;
}
for symbol in query::macro_names(projection, prefix)? {
insert(symbol)?;
}
for symbol in generated_alias_helper_symbols(prefix)? {
insert(symbol)?;
}
for (_, kind_name, ordinal) in projected_tokens(projection, ordered) {
insert(projected_token_symbol(prefix, kind_name, ordinal))?;
}
if ordered {
for symbol in canonical_codec_symbols(projection)? {
insert(symbol)?;
}
}
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Attribute)
{
for symbol in attribute_symbols(model.target_name().as_str())? {
insert(symbol)?;
}
}
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Entity)
{
if let Some(symbol) = create_member_table_symbol(model)? {
insert(symbol)?;
}
for symbol in create_auxiliary_type_symbols(projection, model, prefix)? {
insert(symbol)?;
}
if let Some(symbols) = entity_create_symbols(model)? {
for symbol in symbols {
insert(symbol)?;
}
}
for symbol in entity_reference_symbols(model, prefix)? {
insert(symbol)?;
}
for symbol in entity_complete_symbols(model, prefix)? {
insert(symbol)?;
}
for symbol in entity_crud_symbols(model)? {
insert(symbol)?;
}
}
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Relation)
{
if let Some(symbol) = create_member_table_symbol(model)? {
insert(symbol)?;
}
for symbol in create_auxiliary_type_symbols(projection, model, prefix)? {
insert(symbol)?;
}
for role in model.query_tokens().roles().values() {
let symbols = role_union_symbols(projection, role, prefix)?;
insert(symbols.kind_type)?;
insert(symbols.kind_unknown)?;
insert(symbols.kind_function)?;
insert(symbols.close)?;
for variant in symbols.variants {
insert(variant.kind_constant)?;
insert(variant.from_reference)?;
insert(variant.as_reference)?;
}
}
if let Some(symbols) = entity_create_symbols(model)? {
for symbol in symbols {
insert(symbol)?;
}
}
for symbol in entity_reference_symbols(model, prefix)? {
insert(symbol)?;
}
for symbol in entity_complete_symbols(model, prefix)? {
insert(symbol)?;
}
for symbol in entity_crud_symbols(model)? {
insert(symbol)?;
}
}
if ordered {
for model in projection.models().values() {
for symbol in successor_crud_symbols(model)? {
insert(symbol)?;
}
for operation in successor_batch_operations(model) {
for symbol in successor_batch_function_names(model, operation)? {
insert(symbol)?;
}
}
}
}
Ok(symbols)
}
fn validate_embedded_resource_symbols(
projection: &RuntimeProjection,
prefix: &str,
ordered: bool,
resources: &[(&str, usize)],
) -> Result<(), Diagnostic> {
let mut symbols = validate_generated_symbols(projection, prefix, ordered)?;
let mut insert = |symbol: String| {
if !symbols.insert(symbol) {
return Err(invalid(
"c_emitter_generated_symbol_collision",
"generated C API and embedded-resource symbols collide",
));
}
Ok(())
};
insert(format!("{prefix}_schema_package_chunks_v1"))?;
for (resource, byte_length) in resources {
insert(format!("{prefix}_{resource}_chunks"))?;
for chunk_index in 0..byte_length.div_ceil(C_EMBEDDED_BYTE_CHUNK_MAX) {
insert(format!("{prefix}_{resource}_chunk_{chunk_index}"))?;
}
}
Ok(())
}
fn validate_c_projection_limits(
projection: &RuntimeProjection,
prefix: &str,
ordered: bool,
) -> Result<(), Diagnostic> {
validate_c_translation_inventory(
generated_external_identifiers(projection, prefix, ordered)?.len(),
generated_macro_identifiers(projection, prefix)?.len(),
)
}
fn validate_c_translation_inventory(
generated_external_identifier_count: usize,
generated_macro_identifier_count: usize,
) -> Result<(), Diagnostic> {
let runtime_external_identifier_count = C_RUNTIME_HEADER_EXTERNAL_IDENTIFIER_COUNT;
let runtime_macro_identifier_count = C_RUNTIME_HEADER_MACRO_IDENTIFIER_COUNT;
let external_identifier_count = runtime_external_identifier_count
.checked_add(generated_external_identifier_count)
.expect("C identifier inventory is bounded by the canonical projection limit");
if external_identifier_count > C_TRANSLATION_UNIT_IDENTIFIER_MAX {
return Err(invalid(
"c_emitter_translation_unit_identifier_limit_exceeded",
"generated C file-scope identifiers exceed the 4095-identifier translation ceiling",
));
}
let macro_count = runtime_macro_identifier_count
.checked_add(generated_macro_identifier_count)
.and_then(|count| count.checked_add(C_SUPPORTED_IMPLEMENTATION_MACRO_RESERVE))
.expect("C macro inventory is bounded by the canonical projection limit");
if macro_count > C_SIMULTANEOUS_MACRO_MAX {
return Err(invalid(
"c_emitter_simultaneous_macro_limit_exceeded",
"generated C macros exceed the 4095-identifier translation ceiling",
));
}
Ok(())
}
fn generated_external_identifiers(
projection: &RuntimeProjection,
prefix: &str,
ordered: bool,
) -> Result<BTreeSet<String>, Diagnostic> {
let mut symbols = BTreeSet::new();
symbols.insert(format!("{prefix}_schema_package_open"));
if ordered {
symbols.insert(format!("{prefix}_schema_package_open_v2"));
symbols.insert(format!("{prefix}_migration_catalog_open"));
}
for (_, kind_name, ordinal) in projected_tokens(projection, ordered) {
symbols.insert(projected_token_symbol(prefix, kind_name, ordinal));
}
if ordered {
symbols.extend(canonical_codec_symbols(projection)?);
}
for model in projection.models().values() {
match model.id().kind() {
TypeKind::Attribute => {
symbols.extend(attribute_symbols(model.target_name().as_str())?);
}
TypeKind::Entity => {
if let Some(create) = entity_create_symbols(model)? {
symbols.extend(create);
}
symbols.extend(entity_reference_symbols(model, prefix)?);
symbols.extend(entity_complete_symbols(model, prefix)?);
symbols.extend(entity_crud_symbols(model)?);
}
TypeKind::Relation => {
for role in model.query_tokens().roles().values() {
let union = role_union_symbols(projection, role, prefix)?;
symbols.insert(union.kind_function);
symbols.insert(union.close);
for variant in union.variants {
symbols.insert(variant.from_reference);
symbols.insert(variant.as_reference);
}
}
if let Some(create) = entity_create_symbols(model)? {
symbols.extend(create);
}
symbols.extend(entity_reference_symbols(model, prefix)?);
symbols.extend(entity_complete_symbols(model, prefix)?);
symbols.extend(entity_crud_symbols(model)?);
}
TypeKind::Struct => {}
}
}
Ok(symbols)
}
fn generated_macro_identifiers(
projection: &RuntimeProjection,
prefix: &str,
) -> Result<BTreeSet<String>, Diagnostic> {
let macro_prefix = prefix.to_ascii_uppercase();
let mut symbols = BTreeSet::from([
format!("{macro_prefix}_TYPE_BRIDGE_MODELS_H"),
format!("{macro_prefix}_CREATE_ARGS_VERSION"),
format!("{macro_prefix}_CREATE_FIELD_MAX"),
format!("{macro_prefix}_CREATE_ROLE_MAX"),
format!("{macro_prefix}_CREATE_MEMBER_MAX"),
format!("{macro_prefix}_TRANSLATION_UNIT_IDENTIFIER_MAX"),
format!("{macro_prefix}_SIMULTANEOUS_MACRO_MAX"),
format!("{macro_prefix}_IMPLEMENTATION_MACRO_RESERVE"),
format!("{macro_prefix}_HOSTED_OBJECT_BYTES_MIN"),
format!("{macro_prefix}_EMBEDDED_BYTE_CHUNK_MAX"),
format!("{macro_prefix}_SEQUENCE_OBJECT_BYTES_MAX"),
format!("{macro_prefix}_MIGRATION_HISTORY_RESOURCE"),
]);
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Relation)
{
for role in model.query_tokens().roles().values() {
let union = role_union_symbols(projection, role, prefix)?;
symbols.insert(union.kind_unknown);
symbols.extend(
union
.variants
.into_iter()
.map(|variant| variant.kind_constant),
);
}
}
symbols.extend(query::macro_names(projection, prefix)?);
Ok(symbols)
}
fn render_attribute_declarations(
output: &mut String,
projection: &RuntimeProjection,
_prefix: &str,
) -> Result<(), Diagnostic> {
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Attribute)
{
let value_type = model.declaration().value_type().ok_or_else(|| {
invalid(
"c_emitter_attribute_domain_missing",
"projected C attribute model has no scalar domain",
)
})?;
let abi = attribute_abi(value_type);
let target = model.target_name().as_str();
let [open, value, close] = attribute_symbols(target)?;
let _ = write!(
output,
"\n/* Nominal {domain} attribute `{target}`. */\n\
type_bridge_status_t TYPE_BRIDGE_CALL {open}(\n\
const type_bridge_schema_package_t *package,\n\
{input_type} input,\n\
{target} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {value}(\n\
const {target} *value, {output_type} *out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {close}({target} **value);\n",
domain = value_type.as_str(),
input_type = abi.input_type,
output_type = abi.output_type,
);
}
Ok(())
}
fn render_attribute_definitions(
output: &mut String,
projection: &RuntimeProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
let [add_input, preflight] = generated_alias_helper_symbols(prefix)?;
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Attribute)
{
let value_type = model.declaration().value_type().ok_or_else(|| {
invalid(
"c_emitter_attribute_domain_missing",
"projected C attribute model has no scalar domain",
)
})?;
let abi = attribute_abi(value_type);
let target = model.target_name().as_str();
let [open, value, close] = attribute_symbols(target)?;
let token = model_token_symbol(projection, prefix, model.id())?;
let clear_output = if abi.output_type == "type_bridge_byte_view_t" {
" if (out_value != NULL) {\n out_value->data = NULL;\n out_value->length = 0u;\n }\n"
} else {
" if (out_value != NULL) { *out_value = 0; }\n"
};
let byte_input = if abi.input_type == "type_bridge_byte_view_t" {
format!(
" {add_input}(alias_inputs, &alias_input_count,\n TYPE_BRIDGE_GENERATED_INPUT_BYTES, input.data, input.length);\n"
)
} else {
String::new()
};
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {open}(\n\
const type_bridge_schema_package_t *package,\n\
{input_type} input,\n\
{target} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_value_t *generic_value = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[3];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_SCHEMA_PACKAGE, package, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{token}, 1u);\n\
{byte_input}\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_value, sizeof(*out_value),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_value != NULL) {{ *out_value = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_value == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = {runtime_open}(package, &{token}, input,\n\
&generic_value, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_value = ({target} *)generic_value;\n\
}}\n\
return status;\n\
}}\n\n\
type_bridge_status_t TYPE_BRIDGE_CALL {value}(\n\
const {target} *value, {output_type} *out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_VALUE, value, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_value, sizeof(*out_value),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
{clear_output}\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_value == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_value_validate_model(\n\
(const type_bridge_projected_value_t *)value,\n\
&{token}, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
return {runtime_value}(\n\
(const type_bridge_projected_value_t *)value, out_value);\n\
}}\n\n\
type_bridge_status_t TYPE_BRIDGE_CALL {close}({target} **value) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[1];\n\
size_t alias_input_count = 0u;\n\
type_bridge_projected_value_t *generic_value;\n\
type_bridge_status_t status;\n\
if (value == NULL) {{ return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT; }}\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_VALUE, *value, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
value, sizeof(*value), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
generic_value = (type_bridge_projected_value_t *)*value;\n\
status = type_bridge_projected_value_close(&generic_value);\n\
*value = ({target} *)generic_value;\n\
return status;\n\
}}\n\n",
input_type = abi.input_type,
output_type = abi.output_type,
runtime_open = abi.open_function,
runtime_value = abi.value_function,
clear_output = clear_output,
);
}
Ok(())
}
fn projected_attribute_model<'a>(
projection: &'a RuntimeProjection,
value: &ProjectedTypeRef,
) -> Result<&'a ModelProjection, Diagnostic> {
let ProjectedTypeRef::Model(value) = value else {
return Err(invalid(
"c_emitter_entity_field_not_nominal",
"projected C entity fields must use nominal attribute models",
));
};
if value.id().kind() != TypeKind::Attribute {
return Err(invalid(
"c_emitter_entity_field_not_attribute",
"projected C entity fields must reference attribute models",
));
}
projection.models().get(value.id()).ok_or_else(|| {
invalid(
"c_emitter_entity_attribute_missing",
"projected C entity field references an absent attribute model",
)
})
}
fn projected_member_suffix<'a>(
prefix: &str,
target: &'a TargetIdentifier,
) -> Result<&'a str, Diagnostic> {
target
.as_str()
.strip_prefix(prefix)
.and_then(|value| value.strip_prefix('_'))
.filter(|value| !value.is_empty())
.ok_or_else(|| {
invalid(
"c_emitter_invalid_member_identifier",
"projected C member name is outside the configured symbol prefix",
)
})
}
fn field_token_symbol(
projection: &RuntimeProjection,
prefix: &str,
owner: &type_bridge_contract::id::TypeId,
field: &OwnsFactId,
) -> Result<String, Diagnostic> {
let ordinal = projection
.projected_token_ordinal(&ProjectedTokenIdentity::Field {
owner: owner.clone(),
field: field.clone(),
})
.ok_or_else(|| {
invalid(
"c_emitter_missing_field_token",
"projected C field has no deterministic field-token ordinal",
)
})?;
Ok(projected_token_symbol(prefix, "field", ordinal))
}
fn attribute_type_id(field: &OwnsFactId) -> Result<type_bridge_contract::id::TypeId, Diagnostic> {
type_bridge_contract::id::TypeId::new(TypeKind::Attribute, field.attribute().label().as_str())
}
fn entity_create_symbols(model: &ModelProjection) -> Result<Option<[String; 2]>, Diagnostic> {
model
.create()
.target_name()
.map(|target| {
Ok([
generated_symbol(target.as_str(), "open")?,
generated_symbol(target.as_str(), "close")?,
])
})
.transpose()
}
fn create_args_type(model: &ModelProjection) -> Result<Option<String>, Diagnostic> {
model
.create()
.target_name()
.map(|target| generated_symbol(target.as_str(), "args_v1_t"))
.transpose()
}
fn create_member_table_symbol(model: &ModelProjection) -> Result<Option<String>, Diagnostic> {
if model.create().fields().is_empty() && model.create().roles().is_empty() {
return Ok(None);
}
model
.create()
.target_name()
.map(|target| generated_symbol(target.as_str(), "members_v1"))
.transpose()
}
fn create_member_sequence_type(
model: &ModelProjection,
member: &str,
) -> Result<String, Diagnostic> {
let target = model
.create()
.target_name()
.expect("sequence input is emitted only for constructible models");
generated_symbol(target.as_str(), &format!("{member}_chunks_v1_t"))
}
fn create_auxiliary_type_symbols(
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<Vec<String>, Diagnostic> {
let Some(args) = create_args_type(model)? else {
return Ok(Vec::new());
};
let mut symbols = vec![args];
for field in model.create().fields() {
if field.multiplicity().container() == ProjectedContainer::Sequence {
let member = entity_field_parameter(model, prefix, field.token())?;
projected_attribute_model(projection, field.value())?;
symbols.push(create_member_sequence_type(model, &member)?);
}
}
for role in model.create().roles().values() {
if role.multiplicity().container() == ProjectedContainer::Sequence {
let member = relation_role_parameter(model, prefix, role.role())?;
relation_role_union(model, role.role())?;
symbols.push(create_member_sequence_type(model, &member)?);
}
}
Ok(symbols)
}
fn entity_reference_symbols(
model: &ModelProjection,
prefix: &str,
) -> Result<Vec<String>, Diagnostic> {
let Some(target) = model.reference_read().target_name() else {
return Ok(Vec::new());
};
let mut symbols = vec![
generated_symbol(target.as_str(), "from_iid")?,
generated_symbol(target.as_str(), "iid")?,
generated_symbol(target.as_str(), "close")?,
];
for field in model.reference_read().key_fields() {
let projected = model.query_tokens().fields().get(field).ok_or_else(|| {
invalid(
"c_emitter_reference_key_missing",
"projected C reference key is absent from query fields",
)
})?;
let constructor_suffix = if model.reference_read().key_fields().len() == 1 {
"from_key".to_owned()
} else {
format!(
"from_{}",
projected_member_suffix(prefix, projected.target_name())?
)
};
symbols.push(generated_symbol(target.as_str(), &constructor_suffix)?);
}
for field in model.reference_read().key_fields() {
let projected = model.query_tokens().fields().get(field).ok_or_else(|| {
invalid(
"c_emitter_reference_key_missing",
"projected C reference key is absent from query fields",
)
})?;
symbols.push(generated_symbol(
target.as_str(),
&format!(
"{}_key",
projected_member_suffix(prefix, projected.target_name())?
),
)?);
}
Ok(symbols)
}
fn entity_complete_symbols(
model: &ModelProjection,
prefix: &str,
) -> Result<Vec<String>, Diagnostic> {
let target = model.target_name().as_str();
let mut symbols = vec![
generated_symbol(target, "iid")?,
generated_symbol(target, "reference")?,
generated_symbol(target, "close")?,
];
for field in model.complete_read().fields() {
let projected = model
.query_tokens()
.fields()
.get(field.token())
.ok_or_else(|| {
invalid(
"c_emitter_complete_field_missing",
"projected C complete field is absent from query fields",
)
})?;
let member = projected_member_suffix(prefix, projected.target_name())?;
match field.multiplicity().container() {
ProjectedContainer::Scalar => {
symbols.push(generated_symbol(target, member)?);
}
ProjectedContainer::Sequence => {
symbols.push(generated_symbol(target, &format!("{member}_count"))?);
symbols.push(generated_symbol(target, &format!("{member}_at"))?);
}
}
}
for role in model.complete_read().roles().values() {
let projected = model
.query_tokens()
.roles()
.get(role.role())
.ok_or_else(|| {
invalid(
"c_emitter_complete_role_missing",
"projected C complete role is absent from query role tokens",
)
})?;
let member = projected_member_suffix(prefix, projected.target_name())?;
match role.multiplicity().container() {
ProjectedContainer::Scalar => {
symbols.push(generated_symbol(target, member)?);
}
ProjectedContainer::Sequence => {
symbols.push(generated_symbol(target, &format!("{member}_count"))?);
symbols.push(generated_symbol(target, &format!("{member}_at"))?);
}
}
}
Ok(symbols)
}
fn entity_crud_symbol(model: &ModelProjection, suffix: &str) -> Result<String, Diagnostic> {
generated_symbol(model.target_name().as_str(), suffix)
}
fn entity_crud_symbols(model: &ModelProjection) -> Result<Vec<String>, Diagnostic> {
if model.create().target_name().is_none() {
return Ok(Vec::new());
}
let mut symbols = Vec::new();
for scope in ["database", "read_transaction", "write_transaction"] {
if scope != "read_transaction" && model.create().target_name().is_some() {
for operation in ["insert", "put"] {
symbols.push(entity_crud_symbol(model, &format!("{scope}_{operation}"))?);
}
}
symbols.push(entity_crud_symbol(model, &format!("{scope}_get_by_iid"))?);
if scope != "read_transaction" && model.create().target_name().is_some() {
symbols.push(entity_crud_symbol(model, &format!("{scope}_update"))?);
}
if scope != "read_transaction" {
symbols.push(entity_crud_symbol(
model,
&format!("{scope}_delete_by_iid"),
)?);
}
symbols.push(entity_crud_symbol(model, &format!("{scope}_count"))?);
}
Ok(symbols)
}
#[derive(Clone, Copy)]
struct SuccessorBatchOperation {
name: &'static str,
constant: &'static str,
needs_iid: bool,
needs_create: bool,
has_thing_result: bool,
}
const SUCCESSOR_BATCH_OPERATIONS: [SuccessorBatchOperation; 4] = [
SuccessorBatchOperation {
name: "insert",
constant: "TYPE_BRIDGE_PROJECTED_BATCH_OPERATION_INSERT",
needs_iid: false,
needs_create: true,
has_thing_result: true,
},
SuccessorBatchOperation {
name: "put",
constant: "TYPE_BRIDGE_PROJECTED_BATCH_OPERATION_PUT",
needs_iid: false,
needs_create: true,
has_thing_result: true,
},
SuccessorBatchOperation {
name: "update",
constant: "TYPE_BRIDGE_PROJECTED_BATCH_OPERATION_UPDATE",
needs_iid: true,
needs_create: true,
has_thing_result: true,
},
SuccessorBatchOperation {
name: "delete",
constant: "TYPE_BRIDGE_PROJECTED_BATCH_OPERATION_DELETE",
needs_iid: true,
needs_create: false,
has_thing_result: false,
},
];
fn model_has_reference_key(model: &ModelProjection) -> bool {
!model.reference_read().key_fields().is_empty()
}
fn successor_batch_operations(model: &ModelProjection) -> Vec<SuccessorBatchOperation> {
if model.create().target_name().is_none() {
return Vec::new();
}
SUCCESSOR_BATCH_OPERATIONS
.into_iter()
.filter(|operation| operation.name != "put" || model_has_reference_key(model))
.collect()
}
fn successor_batch_type_names(
model: &ModelProjection,
operation: SuccessorBatchOperation,
) -> Result<[String; 3], Diagnostic> {
let target = model.target_name().as_str();
Ok([
generated_symbol(target, &format!("{}_batch_builder", operation.name))?,
generated_symbol(target, &format!("{}_batch", operation.name))?,
generated_symbol(target, &format!("{}_batch_result", operation.name))?,
])
}
fn successor_crud_symbols(model: &ModelProjection) -> Result<Vec<String>, Diagnostic> {
if model.create().target_name().is_none() {
return Ok(Vec::new());
}
let mut symbols = Vec::new();
for scope in ["database", "read_transaction", "write_transaction"] {
if scope != "read_transaction" {
symbols.push(entity_crud_symbol(model, &format!("{scope}_insert_v2"))?);
if model_has_reference_key(model) {
symbols.push(entity_crud_symbol(model, &format!("{scope}_put_v2"))?);
}
}
symbols.push(entity_crud_symbol(
model,
&format!("{scope}_get_by_iid_v2"),
)?);
if scope != "read_transaction" {
symbols.push(entity_crud_symbol(model, &format!("{scope}_update_v2"))?);
symbols.push(entity_crud_symbol(
model,
&format!("{scope}_delete_by_iid_v2"),
)?);
}
symbols.push(entity_crud_symbol(model, &format!("{scope}_count_v2"))?);
}
Ok(symbols)
}
fn successor_batch_function_names(
model: &ModelProjection,
operation: SuccessorBatchOperation,
) -> Result<Vec<String>, Diagnostic> {
let target = model.target_name().as_str();
let operation_name = operation.name;
let mut symbols = vec![
generated_symbol(target, &format!("{operation_name}_batch_builder_open"))?,
generated_symbol(target, &format!("{operation_name}_batch_builder_add"))?,
generated_symbol(target, &format!("{operation_name}_batch_builder_finish"))?,
generated_symbol(target, &format!("{operation_name}_batch_builder_close"))?,
generated_symbol(target, &format!("{operation_name}_batch_close"))?,
generated_symbol(target, &format!("database_{operation_name}_batch_execute"))?,
generated_symbol(
target,
&format!("write_transaction_{operation_name}_batch_execute"),
)?,
generated_symbol(target, &format!("{operation_name}_batch_result_count"))?,
];
if operation.has_thing_result {
symbols.push(generated_symbol(
target,
&format!("{operation_name}_batch_result_thing_at"),
)?);
}
symbols.push(generated_symbol(
target,
&format!("{operation_name}_batch_result_close"),
)?);
Ok(symbols)
}
fn render_successor_model_api(
output: &mut String,
projection: &RuntimeProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
output.push_str("\n/* Policy-aware nominal data operations. */\n");
for model in projection.models().values().filter(|model| {
matches!(model.id().kind(), TypeKind::Entity | TypeKind::Relation)
&& model.create().target_name().is_some()
}) {
let kind = match model.id().kind() {
TypeKind::Entity => "entity",
TypeKind::Relation => "relation",
_ => unreachable!(),
};
render_successor_model_crud(output, projection, model, prefix, kind)?;
for operation in successor_batch_operations(model) {
render_successor_model_batch(output, projection, model, prefix, operation)?;
}
}
Ok(())
}
fn render_successor_model_crud(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
kind: &str,
) -> Result<(), Diagnostic> {
let create = model
.create()
.target_name()
.expect("successor CRUD is emitted only for constructible models")
.as_str();
let target = model.target_name().as_str();
let model_token = model_token_symbol(projection, prefix, model.id())?;
let [add_input, preflight] = generated_alias_helper_symbols(prefix)?;
for (scope, owner) in [
("database", "type_bridge_database_t"),
("read_transaction", "type_bridge_read_transaction_t"),
("write_transaction", "type_bridge_write_transaction_t"),
] {
let owner_kind = match scope {
"database" => "TYPE_BRIDGE_GENERATED_INPUT_DATABASE",
"read_transaction" => "TYPE_BRIDGE_GENERATED_INPUT_READ_TRANSACTION",
"write_transaction" => "TYPE_BRIDGE_GENERATED_INPUT_WRITE_TRANSACTION",
_ => unreachable!(),
};
if scope != "read_transaction" {
for operation in ["insert", "put"] {
if operation == "put" && !model_has_reference_key(model) {
continue;
}
let symbol = entity_crud_symbol(model, &format!("{scope}_{operation}_v2"))?;
let runtime = format!("type_bridge_{scope}_{kind}_{operation}_v2");
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {symbol}(\n\
const {owner} *owner, const {create} *create,\n\
const type_bridge_query_execution_limits_v1_t *limits,\n\
const type_bridge_cancellation_t *cancellation,\n\
{target} **out_entity,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_thing_t *generic_entity = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[5];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
{owner_kind}, owner, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_CREATE, create, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, limits, sizeof(*limits));\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_entity, sizeof(*out_entity),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_entity != NULL) {{ *out_entity = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_entity == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = {runtime}(owner, &{model_token},\n\
(const type_bridge_projected_create_t *)create, limits, cancellation,\n\
&generic_entity, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_entity = ({target} *)generic_entity;\n\
}}\n\
return status;\n\
}}\n"
);
}
}
let get = entity_crud_symbol(model, &format!("{scope}_get_by_iid_v2"))?;
let runtime_get = format!("type_bridge_{scope}_{kind}_get_by_iid_v2");
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {get}(\n\
const {owner} *owner, type_bridge_byte_view_t iid,\n\
const type_bridge_query_execution_limits_v1_t *limits,\n\
const type_bridge_cancellation_t *cancellation,\n\
{target} **out_entity,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_thing_t *generic_entity = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[5];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
{owner_kind}, owner, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, iid.data, iid.length);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, limits, sizeof(*limits));\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_entity, sizeof(*out_entity),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_entity != NULL) {{ *out_entity = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_entity == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = {runtime_get}(owner, &{model_token}, iid, limits, cancellation,\n\
&generic_entity, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_entity = ({target} *)generic_entity;\n\
}}\n\
return status;\n\
}}\n"
);
if scope != "read_transaction" {
let update = entity_crud_symbol(model, &format!("{scope}_update_v2"))?;
let runtime_update = format!("type_bridge_{scope}_{kind}_update_v2");
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {update}(\n\
const {owner} *owner, type_bridge_byte_view_t iid,\n\
const {create} *replacement,\n\
const type_bridge_query_execution_limits_v1_t *limits,\n\
const type_bridge_cancellation_t *cancellation,\n\
{target} **out_entity,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_thing_t *generic_entity = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[6];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
{owner_kind}, owner, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, iid.data, iid.length);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_CREATE, replacement, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, limits, sizeof(*limits));\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_entity, sizeof(*out_entity),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_entity != NULL) {{ *out_entity = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_entity == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = {runtime_update}(owner, &{model_token}, iid,\n\
(const type_bridge_projected_create_t *)replacement, limits, cancellation,\n\
&generic_entity, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_entity = ({target} *)generic_entity;\n\
}}\n\
return status;\n\
}}\n"
);
let delete = entity_crud_symbol(model, &format!("{scope}_delete_by_iid_v2"))?;
let runtime_delete = format!("type_bridge_{scope}_{kind}_delete_by_iid_v2");
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {delete}(\n\
const {owner} *owner, type_bridge_byte_view_t iid,\n\
const type_bridge_query_execution_limits_v1_t *limits,\n\
const type_bridge_cancellation_t *cancellation,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[5];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
{owner_kind}, owner, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, iid.data, iid.length);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, limits, sizeof(*limits));\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_diagnostics, sizeof(*out_diagnostics), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
return {runtime_delete}(owner, &{model_token}, iid, limits, cancellation,\n\
out_diagnostics);\n\
}}\n"
);
}
let count = entity_crud_symbol(model, &format!("{scope}_count_v2"))?;
let runtime_count = format!("type_bridge_{scope}_{kind}_count_v2");
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {count}(\n\
const {owner} *owner,\n\
const type_bridge_query_execution_limits_v1_t *limits,\n\
const type_bridge_cancellation_t *cancellation, uint64_t *out_count,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[4];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
{owner_kind}, owner, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, limits, sizeof(*limits));\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_count, sizeof(*out_count),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_count != NULL) {{ *out_count = 0u; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_count == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
return {runtime_count}(owner, &{model_token}, limits, cancellation,\n\
out_count, out_diagnostics);\n\
}}\n"
);
}
Ok(())
}
fn render_successor_model_batch(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
operation: SuccessorBatchOperation,
) -> Result<(), Diagnostic> {
let [builder, batch, result] = successor_batch_type_names(model, operation)?;
let functions = successor_batch_function_names(model, operation)?;
let mut function = functions.iter();
let open = function.next().expect("batch open symbol exists");
let add = function.next().expect("batch add symbol exists");
let finish = function.next().expect("batch finish symbol exists");
let builder_close = function.next().expect("batch builder close symbol exists");
let batch_close = function.next().expect("batch close symbol exists");
let database_execute = function.next().expect("database execute symbol exists");
let transaction_execute = function.next().expect("transaction execute symbol exists");
let count = function.next().expect("batch result count symbol exists");
let thing_at = operation
.has_thing_result
.then(|| function.next().expect("batch result thing symbol exists"));
let result_close = function.next().expect("batch result close symbol exists");
debug_assert!(function.next().is_none());
let model_token = model_token_symbol(projection, prefix, model.id())?;
let target = model.target_name().as_str();
let create = model
.create()
.target_name()
.expect("batch API is emitted only for constructible models")
.as_str();
let [add_input, preflight] = generated_alias_helper_symbols(prefix)?;
let _ = write!(
output,
"\nstatic inline type_bridge_status_t TYPE_BRIDGE_CALL {open}(\n\
const type_bridge_schema_package_t *package,\n\
const type_bridge_query_execution_limits_v1_t *construction_limits,\n\
const type_bridge_cancellation_t *cancellation, {builder} **out_builder,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_batch_builder_t *generic_builder = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[4];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_SCHEMA_PACKAGE, package, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, construction_limits,\n\
sizeof(*construction_limits));\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_builder, sizeof(*out_builder),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_builder != NULL) {{ *out_builder = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_builder == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_batch_builder_open_v1(\n\
package, &{model_token}, {operation_constant}, construction_limits, cancellation,\n\
&generic_builder, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_builder = ({builder} *)generic_builder;\n\
}}\n\
return status;\n\
}}\n",
operation_constant = operation.constant,
);
match (operation.needs_iid, operation.needs_create) {
(false, true) => {
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {add}(\n\
{builder} *builder, const {create} *create,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
const type_bridge_byte_view_t iid = {{ NULL, 0u }};\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_BATCH_BUILDER, builder, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_CREATE, create, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_diagnostics, sizeof(*out_diagnostics), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
return type_bridge_projected_batch_builder_add_v1(\n\
(type_bridge_projected_batch_builder_t *)builder, iid,\n\
(const type_bridge_projected_create_t *)create, out_diagnostics);\n\
}}\n"
);
}
(true, true) => {
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {add}(\n\
{builder} *builder, type_bridge_byte_view_t iid,\n\
const {create} *replacement,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[3];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_BATCH_BUILDER, builder, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, iid.data, iid.length);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_CREATE, replacement, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_diagnostics, sizeof(*out_diagnostics), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
return type_bridge_projected_batch_builder_add_v1(\n\
(type_bridge_projected_batch_builder_t *)builder, iid,\n\
(const type_bridge_projected_create_t *)replacement, out_diagnostics);\n\
}}\n"
);
}
(true, false) => {
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {add}(\n\
{builder} *builder, type_bridge_byte_view_t iid,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_BATCH_BUILDER, builder, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, iid.data, iid.length);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_diagnostics, sizeof(*out_diagnostics), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
return type_bridge_projected_batch_builder_add_v1(\n\
(type_bridge_projected_batch_builder_t *)builder, iid, NULL,\n\
out_diagnostics);\n\
}}\n"
);
}
(false, false) => unreachable!(),
}
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {finish}(\n\
{builder} **builder, {batch} **out_batch,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_batch_builder_t *generic_builder =\n\
builder == NULL ? NULL : (type_bridge_projected_batch_builder_t *)*builder;\n\
type_bridge_projected_batch_t *generic_batch = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[3];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_BATCH_BUILDER, generic_builder, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
builder, sizeof(*builder), out_batch, sizeof(*out_batch));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
alias_input_count = 0u;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_BATCH_BUILDER, generic_builder, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, builder, sizeof(*builder));\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, out_batch, sizeof(*out_batch));\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_diagnostics, sizeof(*out_diagnostics), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_batch != NULL) {{ *out_batch = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (builder == NULL || out_batch == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_batch_builder_finish(\n\
&generic_builder, &generic_batch, out_diagnostics);\n\
*builder = ({builder} *)generic_builder;\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_batch = ({batch} *)generic_batch;\n\
}}\n\
return status;\n\
}}\n\
static inline type_bridge_status_t TYPE_BRIDGE_CALL {builder_close}({builder} **builder) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[1];\n\
size_t alias_input_count = 0u;\n\
type_bridge_projected_batch_builder_t *generic_builder;\n\
type_bridge_status_t status;\n\
if (builder == NULL) {{ return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT; }}\n\
generic_builder = (type_bridge_projected_batch_builder_t *)*builder;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_BATCH_BUILDER, generic_builder, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
builder, sizeof(*builder), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
status = type_bridge_projected_batch_builder_close(&generic_builder);\n\
*builder = ({builder} *)generic_builder;\n\
return status;\n\
}}\n\
static inline type_bridge_status_t TYPE_BRIDGE_CALL {batch_close}({batch} **batch) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[1];\n\
size_t alias_input_count = 0u;\n\
type_bridge_projected_batch_t *generic_batch;\n\
type_bridge_status_t status;\n\
if (batch == NULL) {{ return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT; }}\n\
generic_batch = (type_bridge_projected_batch_t *)*batch;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_BATCH, generic_batch, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
batch, sizeof(*batch), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
status = type_bridge_projected_batch_close(&generic_batch);\n\
*batch = ({batch} *)generic_batch;\n\
return status;\n\
}}\n"
);
for (owner_type, owner_kind, execute, runtime) in [
(
"type_bridge_database_t",
"TYPE_BRIDGE_GENERATED_INPUT_DATABASE",
database_execute,
"type_bridge_database_projected_batch_execute_v1",
),
(
"type_bridge_write_transaction_t",
"TYPE_BRIDGE_GENERATED_INPUT_WRITE_TRANSACTION",
transaction_execute,
"type_bridge_write_transaction_projected_batch_execute_v1",
),
] {
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {execute}(\n\
const {owner_type} *owner, const {batch} *batch,\n\
const type_bridge_query_execution_limits_v1_t *limits,\n\
const type_bridge_cancellation_t *cancellation, {result} **out_result,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_batch_result_t *generic_result = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[4];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
{owner_kind}, owner, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_BATCH, batch, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, limits, sizeof(*limits));\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_result, sizeof(*out_result),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_result != NULL) {{ *out_result = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_result == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = {runtime}(owner, (const type_bridge_projected_batch_t *)batch,\n\
limits, cancellation,\n\
&generic_result, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_result = ({result} *)generic_result;\n\
}}\n\
return status;\n\
}}\n"
);
}
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {count}(\n\
const {result} *result, size_t *out_count,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_BATCH_RESULT, result, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_count, sizeof(*out_count),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_count != NULL) {{ *out_count = 0u; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_count == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
return type_bridge_projected_batch_result_count(\n\
(const type_bridge_projected_batch_result_t *)result, &{model_token},\n\
{operation_constant}, out_count, out_diagnostics);\n\
}}\n",
operation_constant = operation.constant,
);
if let Some(thing_at) = thing_at {
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {thing_at}(\n\
const {result} *result, size_t index, {target} **out_entity,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_thing_t *generic_entity = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_BATCH_RESULT, result, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_entity, sizeof(*out_entity),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_entity != NULL) {{ *out_entity = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_entity == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_batch_result_thing_at(\n\
(const type_bridge_projected_batch_result_t *)result, &{model_token},\n\
{operation_constant}, index,\n\
&generic_entity, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_entity = ({target} *)generic_entity;\n\
}}\n\
return status;\n\
}}\n",
operation_constant = operation.constant,
);
}
let _ = write!(
output,
"static inline type_bridge_status_t TYPE_BRIDGE_CALL {result_close}({result} **result) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[1];\n\
size_t alias_input_count = 0u;\n\
type_bridge_projected_batch_result_t *generic_result;\n\
type_bridge_status_t status;\n\
if (result == NULL) {{ return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT; }}\n\
generic_result = (type_bridge_projected_batch_result_t *)*result;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_BATCH_RESULT, generic_result, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
result, sizeof(*result), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
status = type_bridge_projected_batch_result_close(&generic_result);\n\
*result = ({result} *)generic_result;\n\
return status;\n\
}}\n"
);
Ok(())
}
fn render_codec_declaration_pair(output: &mut String, target: &str) -> Result<(), Diagnostic> {
let encode = generated_symbol(target, "canonical_encode")?;
let decode = generated_symbol(target, "canonical_decode")?;
let _ = write!(
output,
"\ntype_bridge_status_t TYPE_BRIDGE_CALL {encode}(\n\
const {target} *value, type_bridge_canonical_bytes_t **out_bytes,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {decode}(\n\
const type_bridge_schema_package_t *package, type_bridge_byte_view_t bytes,\n\
{target} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
);
Ok(())
}
fn canonical_codec_symbols(projection: &RuntimeProjection) -> Result<BTreeSet<String>, Diagnostic> {
fn add_pair(symbols: &mut BTreeSet<String>, target: &str) -> Result<(), Diagnostic> {
symbols.insert(generated_symbol(target, "canonical_encode")?);
symbols.insert(generated_symbol(target, "canonical_decode")?);
Ok(())
}
let mut symbols = BTreeSet::new();
for model in projection.models().values() {
match model.id().kind() {
TypeKind::Attribute => add_pair(&mut symbols, model.target_name().as_str())?,
TypeKind::Entity | TypeKind::Relation => {
if let Some(target) = model.create().target_name() {
add_pair(&mut symbols, target.as_str())?;
}
if let Some(target) = model.reference_read().target_name() {
add_pair(&mut symbols, target.as_str())?;
}
add_pair(&mut symbols, model.target_name().as_str())?;
}
TypeKind::Struct => unreachable!("structs have their own projection map"),
}
}
for structure in projection.structs().values() {
add_pair(&mut symbols, structure.target_name().as_str())?;
symbols.insert(generated_symbol(
structure.target_name().as_str(),
"canonical_close",
)?);
for field in structure.fields() {
symbols.insert(generated_symbol(
structure.target_name().as_str(),
&format!("{}_member", field.target_name().as_str()),
)?);
}
}
Ok(symbols)
}
fn render_canonical_codec_declarations(
output: &mut String,
projection: &RuntimeProjection,
) -> Result<(), Diagnostic> {
for model in projection.models().values() {
match model.id().kind() {
TypeKind::Attribute => {
render_codec_declaration_pair(output, model.target_name().as_str())?;
}
TypeKind::Entity | TypeKind::Relation => {
if let Some(target) = model.create().target_name() {
render_codec_declaration_pair(output, target.as_str())?;
}
if let Some(target) = model.reference_read().target_name() {
render_codec_declaration_pair(output, target.as_str())?;
}
render_codec_declaration_pair(output, model.target_name().as_str())?;
}
TypeKind::Struct => unreachable!("structs have their own projection map"),
}
}
for structure in projection.structs().values() {
render_codec_declaration_pair(output, structure.target_name().as_str())?;
let close = generated_symbol(structure.target_name().as_str(), "canonical_close")?;
let _ = writeln!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {close}({} **value);",
structure.target_name().as_str(),
);
for field in structure.fields() {
let member = generated_symbol(
structure.target_name().as_str(),
&format!("{}_member", field.target_name().as_str()),
)?;
let _ = writeln!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {member}(\n const {} *value,\n type_bridge_projected_struct_member_t **out_member,\n type_bridge_execution_diagnostics_t **out_diagnostics);",
structure.target_name().as_str(),
);
}
}
Ok(())
}
fn render_codec_definition_pair(
output: &mut String,
target: &str,
generic: &str,
encode_runtime: &str,
decode_runtime: &str,
token: &str,
) -> Result<(), Diagnostic> {
let encode = generated_symbol(target, "canonical_encode")?;
let decode = generated_symbol(target, "canonical_decode")?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {encode}(\n\
const {target} *value, type_bridge_canonical_bytes_t **out_bytes,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
return {encode_runtime}((const {generic} *)value, NULL, out_bytes, out_diagnostics);\n\
}}\n\n\
type_bridge_status_t TYPE_BRIDGE_CALL {decode}(\n\
const type_bridge_schema_package_t *package, type_bridge_byte_view_t bytes,\n\
{target} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
{generic} *generic_value = NULL;\n\
type_bridge_status_t status;\n\
if (out_value != NULL) {{ *out_value = NULL; }}\n\
status = {decode_runtime}(package, bytes, &{token}, NULL,\n\
&generic_value, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{ *out_value = ({target} *)generic_value; }}\n\
return status;\n\
}}\n\n",
);
Ok(())
}
fn render_canonical_codec_definitions(
output: &mut String,
projection: &RuntimeProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
for model in projection.models().values() {
match model.id().kind() {
TypeKind::Attribute => {
let attribute =
type_bridge_contract::id::AttributeId::new(model.id().label().as_str())?;
let token = attribute_token_symbol(projection, prefix, &attribute)?;
render_codec_definition_pair(
output,
model.target_name().as_str(),
"type_bridge_projected_value_t",
"type_bridge_canonical_record_encode_attribute_v1",
"type_bridge_canonical_record_decode_attribute_v1",
&token,
)?;
}
TypeKind::Entity | TypeKind::Relation => {
let token = model_token_symbol(projection, prefix, model.id())?;
if let Some(target) = model.create().target_name() {
render_codec_definition_pair(
output,
target.as_str(),
"type_bridge_projected_create_t",
"type_bridge_canonical_record_encode_create_v1",
"type_bridge_canonical_record_decode_create_v1",
&token,
)?;
}
if let Some(target) = model.reference_read().target_name() {
render_codec_definition_pair(
output,
target.as_str(),
"type_bridge_projected_reference_t",
"type_bridge_canonical_record_encode_reference_v1",
"type_bridge_canonical_record_decode_reference_v1",
&token,
)?;
}
render_codec_definition_pair(
output,
model.target_name().as_str(),
"type_bridge_projected_thing_t",
"type_bridge_canonical_record_encode_snapshot_v1",
"type_bridge_canonical_record_decode_snapshot_v1",
&token,
)?;
}
TypeKind::Struct => unreachable!("structs have their own projection map"),
}
}
for structure in projection.structs().values() {
let token = struct_token_symbol(projection, prefix, structure.id())?;
let target = structure.target_name().as_str();
render_codec_definition_pair(
output,
target,
"type_bridge_projected_struct_t",
"type_bridge_canonical_record_encode_struct_v1",
"type_bridge_canonical_record_decode_struct_v1",
&token,
)?;
let close = generated_symbol(target, "canonical_close")?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {close}({target} **value) {{\n\
type_bridge_projected_struct_t *generic_value;\n\
type_bridge_status_t status;\n\
if (value == NULL) {{ return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT; }}\n\
generic_value = (type_bridge_projected_struct_t *)*value;\n\
status = type_bridge_projected_struct_close(&generic_value);\n\
*value = ({target} *)generic_value;\n\
return status;\n\
}}\n\n",
);
for (index, field) in structure.fields().iter().enumerate() {
let member =
generated_symbol(target, &format!("{}_member", field.target_name().as_str()))?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {member}(\n\
const {target} *value,\n\
type_bridge_projected_struct_member_t **out_member,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
return type_bridge_projected_struct_member_at_v1(\n\
(const type_bridge_projected_struct_t *)value, &{token}, {index}u,\n\
out_member, out_diagnostics);\n\
}}\n\n",
);
}
}
Ok(())
}
fn render_entity_model_declarations(
output: &mut String,
projection: &RuntimeProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Entity)
{
render_entity_create_declaration(output, projection, model, prefix)?;
render_entity_reference_declarations(output, projection, model, prefix)?;
render_entity_complete_declarations(output, projection, model, prefix)?;
render_model_crud_declarations(output, model, "entity")?;
}
Ok(())
}
fn render_relation_model_declarations(
output: &mut String,
projection: &RuntimeProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Relation)
{
render_relation_create_declaration(output, projection, model, prefix)?;
render_entity_reference_declarations(output, projection, model, prefix)?;
render_relation_complete_declarations(output, projection, model, prefix)?;
render_model_crud_declarations(output, model, "relation")?;
}
Ok(())
}
fn render_entity_create_declaration(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
if !model.create().roles().is_empty() {
return Err(invalid(
"c_emitter_entity_create_has_roles",
"projected C entity construction cannot contain relation roles",
));
}
render_create_declaration(output, projection, model, prefix, "entity")
}
fn relation_role_parameter(
model: &ModelProjection,
prefix: &str,
role: &type_bridge_contract::id::RoleId,
) -> Result<String, Diagnostic> {
let projected = model.query_tokens().roles().get(role).ok_or_else(|| {
invalid(
"c_emitter_relation_role_missing",
"projected C relation role is absent from query role tokens",
)
})?;
generated_symbol(
"role",
projected_member_suffix(prefix, projected.target_name())?,
)
}
fn relation_role_union<'a>(
model: &'a ModelProjection,
role: &type_bridge_contract::id::RoleId,
) -> Result<&'a TargetIdentifier, Diagnostic> {
model
.query_tokens()
.roles()
.get(role)
.and_then(RoleTokenProjection::player_union_target_name)
.ok_or_else(|| {
invalid(
"c_emitter_relation_role_union_missing",
"projected C relation role is missing its nominal player union",
)
})
}
fn render_relation_create_declaration(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
render_create_declaration(output, projection, model, prefix, "relation")
}
fn render_create_declaration(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
kind: &str,
) -> Result<(), Diagnostic> {
let Some(target) = model.create().target_name() else {
return Ok(());
};
let [open, close] = entity_create_symbols(model)?.expect("create target was checked");
let args = create_args_type(model)?.expect("create target was checked");
let macro_prefix = prefix.to_ascii_uppercase();
for field in model.create().fields() {
if field.multiplicity().container() != ProjectedContainer::Sequence {
continue;
}
let attribute = projected_attribute_model(projection, field.value())?;
let member = entity_field_parameter(model, prefix, field.token())?;
let chunks = create_member_sequence_type(model, &member)?;
let _ = write!(
output,
"\n/* Each linked chunk is nonempty, contains no NULL handles, and its\n\
* values array count is at most\n\
* {macro_prefix}_SEQUENCE_OBJECT_BYTES_MAX / sizeof(values[0]).\n\
* The aggregate chain count is at most\n\
* TYPE_BRIDGE_PROJECTED_COLLECTION_LEN_MAX. */\n\
typedef struct {chunks} {chunks};\n\
struct {chunks} {{\n\
size_t struct_size;\n\
uint32_t version;\n\
const {element} *const *values;\n\
size_t count;\n\
const {chunks} *next;\n\
uint32_t reserved[4];\n\
}};\n\
#if defined(__cplusplus)\n\
static_assert(sizeof({chunks}) <= {macro_prefix}_HOSTED_OBJECT_BYTES_MIN,\n\
\"generated create sequence chunk exceeds the C hosted-object minimum\");\n\
static_assert(sizeof({chunks}) ==\n\
sizeof(type_bridge_generated_create_handle_chunk_v1_t) &&\n\
offsetof({chunks}, struct_size) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, struct_size) &&\n\
offsetof({chunks}, version) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, version) &&\n\
offsetof({chunks}, values) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, values) &&\n\
offsetof({chunks}, count) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, count) &&\n\
offsetof({chunks}, next) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, next) &&\n\
offsetof({chunks}, reserved) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, reserved),\n\
\"generated create sequence chunk layout differs from the runtime graph ABI\");\n\
#else\n\
_Static_assert(sizeof({chunks}) <= {macro_prefix}_HOSTED_OBJECT_BYTES_MIN,\n\
\"generated create sequence chunk exceeds the C hosted-object minimum\");\n\
_Static_assert(sizeof({chunks}) ==\n\
sizeof(type_bridge_generated_create_handle_chunk_v1_t) &&\n\
offsetof({chunks}, struct_size) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, struct_size) &&\n\
offsetof({chunks}, version) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, version) &&\n\
offsetof({chunks}, values) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, values) &&\n\
offsetof({chunks}, count) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, count) &&\n\
offsetof({chunks}, next) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, next) &&\n\
offsetof({chunks}, reserved) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, reserved),\n\
\"generated create sequence chunk layout differs from the runtime graph ABI\");\n\
#endif\n",
element = attribute.target_name().as_str(),
);
}
for role in model.create().roles().values() {
if role.multiplicity().container() != ProjectedContainer::Sequence {
continue;
}
let union = relation_role_union(model, role.role())?;
let member = relation_role_parameter(model, prefix, role.role())?;
let chunks = create_member_sequence_type(model, &member)?;
let _ = write!(
output,
"\n/* Each linked chunk is nonempty, contains no NULL handles, and its\n\
* values array count is at most\n\
* {macro_prefix}_SEQUENCE_OBJECT_BYTES_MAX / sizeof(values[0]).\n\
* The aggregate chain count is at most\n\
* TYPE_BRIDGE_PROJECTED_COLLECTION_LEN_MAX. */\n\
typedef struct {chunks} {chunks};\n\
struct {chunks} {{\n\
size_t struct_size;\n\
uint32_t version;\n\
const {element} *const *values;\n\
size_t count;\n\
const {chunks} *next;\n\
uint32_t reserved[4];\n\
}};\n\
#if defined(__cplusplus)\n\
static_assert(sizeof({chunks}) <= {macro_prefix}_HOSTED_OBJECT_BYTES_MIN,\n\
\"generated create sequence chunk exceeds the C hosted-object minimum\");\n\
static_assert(sizeof({chunks}) ==\n\
sizeof(type_bridge_generated_create_handle_chunk_v1_t) &&\n\
offsetof({chunks}, struct_size) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, struct_size) &&\n\
offsetof({chunks}, version) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, version) &&\n\
offsetof({chunks}, values) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, values) &&\n\
offsetof({chunks}, count) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, count) &&\n\
offsetof({chunks}, next) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, next) &&\n\
offsetof({chunks}, reserved) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, reserved),\n\
\"generated create sequence chunk layout differs from the runtime graph ABI\");\n\
#else\n\
_Static_assert(sizeof({chunks}) <= {macro_prefix}_HOSTED_OBJECT_BYTES_MIN,\n\
\"generated create sequence chunk exceeds the C hosted-object minimum\");\n\
_Static_assert(sizeof({chunks}) ==\n\
sizeof(type_bridge_generated_create_handle_chunk_v1_t) &&\n\
offsetof({chunks}, struct_size) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, struct_size) &&\n\
offsetof({chunks}, version) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, version) &&\n\
offsetof({chunks}, values) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, values) &&\n\
offsetof({chunks}, count) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, count) &&\n\
offsetof({chunks}, next) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, next) &&\n\
offsetof({chunks}, reserved) == offsetof(\n\
type_bridge_generated_create_handle_chunk_v1_t, reserved),\n\
\"generated create sequence chunk layout differs from the runtime graph ABI\");\n\
#endif\n",
element = union.as_str(),
);
}
let _ = write!(
output,
"\n/* Versioned nominal one-shot create arguments for {kind} `{}`. */\n\
typedef struct {args} {{\n\
size_t struct_size;\n\
uint32_t version;\n",
model.target_name().as_str(),
);
for field in model.create().fields() {
let attribute = projected_attribute_model(projection, field.value())?;
let member = entity_field_parameter(model, prefix, field.token())?;
match field.multiplicity().container() {
ProjectedContainer::Scalar => {
let _ = writeln!(
output,
" const {} *{member};",
attribute.target_name().as_str(),
);
}
ProjectedContainer::Sequence => {
let chunks = create_member_sequence_type(model, &member)?;
let _ = writeln!(output, " const {chunks} *{member}_chunks;");
}
}
}
for role in model.create().roles().values() {
let union = relation_role_union(model, role.role())?;
let member = relation_role_parameter(model, prefix, role.role())?;
match role.multiplicity().container() {
ProjectedContainer::Scalar => {
let _ = writeln!(output, " const {} *{member};", union.as_str());
}
ProjectedContainer::Sequence => {
let chunks = create_member_sequence_type(model, &member)?;
let _ = writeln!(output, " const {chunks} *{member}_chunks;");
}
}
}
let _ = write!(
output,
" uint32_t reserved[4];\n\
}} {args};\n\
#if defined(__cplusplus)\n\
static_assert(sizeof({args}) <= {macro_prefix}_HOSTED_OBJECT_BYTES_MIN,\n\
\"generated create args exceed the C hosted-object minimum\");\n\
#else\n\
_Static_assert(sizeof({args}) <= {macro_prefix}_HOSTED_OBJECT_BYTES_MIN,\n\
\"generated create args exceed the C hosted-object minimum\");\n\
#endif\n\
type_bridge_status_t TYPE_BRIDGE_CALL {open}(\n\
const type_bridge_schema_package_t *package,\n",
);
let _ = write!(
output,
" const {args} *args,\n\
{target} **out_create,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {close}({target} **create);\n",
target = target.as_str(),
);
Ok(())
}
fn entity_field_parameter(
model: &ModelProjection,
prefix: &str,
field: &OwnsFactId,
) -> Result<String, Diagnostic> {
let projected = model.query_tokens().fields().get(field).ok_or_else(|| {
invalid(
"c_emitter_entity_field_missing",
"projected C entity field is absent from query fields",
)
})?;
generated_symbol(
"field",
projected_member_suffix(prefix, projected.target_name())?,
)
}
fn render_entity_reference_declarations(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
let Some(target) = model.reference_read().target_name() else {
return Ok(());
};
let symbols = entity_reference_symbols(model, prefix)?;
let from_iid = &symbols[0];
let iid = &symbols[1];
let close = &symbols[2];
let _ = write!(
output,
"\n/* Nominal identity reference for `{}`. */\n\
type_bridge_status_t TYPE_BRIDGE_CALL {from_iid}(\n\
const type_bridge_schema_package_t *package,\n\
type_bridge_byte_view_t iid,\n\
{target} **out_reference,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
model.target_name().as_str(),
target = target.as_str(),
);
let mut symbol_index = 3;
for field in model.reference_read().key_fields() {
let constructor = &symbols[symbol_index];
symbol_index += 1;
let projected = model.query_tokens().fields().get(field).ok_or_else(|| {
invalid(
"c_emitter_reference_key_missing",
"projected C reference key is absent from query fields",
)
})?;
let member = projected_member_suffix(prefix, projected.target_name())?;
let attribute_id = attribute_type_id(field)?;
let attribute = projection.models().get(&attribute_id).ok_or_else(|| {
invalid(
"c_emitter_entity_attribute_missing",
"projected C reference key attribute is absent",
)
})?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {constructor}(\n\
const type_bridge_schema_package_t *package,\n\
const {attribute} *key_{member},\n\
{target} **out_reference,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
target = target.as_str(),
attribute = attribute.target_name().as_str(),
);
}
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {iid}(\n\
const {target} *reference, type_bridge_byte_view_t *out_iid,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
target = target.as_str(),
);
for field in model.reference_read().key_fields() {
let projected = model.query_tokens().fields().get(field).ok_or_else(|| {
invalid(
"c_emitter_reference_key_missing",
"projected C reference key is absent from query fields",
)
})?;
let attribute_id = attribute_type_id(field)?;
let attribute = projection.models().get(&attribute_id).ok_or_else(|| {
invalid(
"c_emitter_entity_attribute_missing",
"projected C reference key attribute is absent",
)
})?;
let getter = &symbols[symbol_index];
symbol_index += 1;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {getter}(\n\
const {target} *reference,\n\
{attribute} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
target = target.as_str(),
attribute = attribute.target_name().as_str(),
);
let _ = projected;
}
let _ = writeln!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {close}({} **reference);",
target.as_str(),
);
Ok(())
}
fn render_entity_complete_declarations(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
let target = model.target_name().as_str();
let reference = model.reference_read().target_name().ok_or_else(|| {
invalid(
"c_emitter_entity_reference_missing",
"projected C entity must expose a nominal reference",
)
})?;
let symbols = entity_complete_symbols(model, prefix)?;
let _ = write!(
output,
"\n/* Immutable completely hydrated entity `{target}`. */\n\
type_bridge_status_t TYPE_BRIDGE_CALL {}(\n\
const {target} *entity, type_bridge_byte_view_t *out_iid,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {}(\n\
const {target} *entity,\n\
{reference} **out_reference,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
symbols[0],
symbols[1],
reference = reference.as_str(),
);
let mut symbol_index = 3;
for field in model.complete_read().fields() {
let attribute = projected_attribute_model(projection, field.value())?;
match field.multiplicity().container() {
ProjectedContainer::Scalar => {
let accessor = &symbols[symbol_index];
symbol_index += 1;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {accessor}(\n\
const {target} *entity,\n\
{attribute} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
attribute = attribute.target_name().as_str(),
);
}
ProjectedContainer::Sequence => {
let count = &symbols[symbol_index];
let at = &symbols[symbol_index + 1];
symbol_index += 2;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {count}(\n\
const {target} *entity, size_t *out_count,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {at}(\n\
const {target} *entity, size_t index,\n\
{attribute} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
attribute = attribute.target_name().as_str(),
);
}
}
}
let _ = writeln!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {}({target} **entity);",
symbols[2],
);
Ok(())
}
fn render_relation_complete_declarations(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
let target = model.target_name().as_str();
let reference = model.reference_read().target_name().ok_or_else(|| {
invalid(
"c_emitter_relation_reference_missing",
"projected C relation must expose a nominal reference",
)
})?;
let symbols = entity_complete_symbols(model, prefix)?;
let _ = write!(
output,
"\n/* Immutable completely hydrated relation `{target}`. */\n\
type_bridge_status_t TYPE_BRIDGE_CALL {}(\n\
const {target} *relation, type_bridge_byte_view_t *out_iid,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {}(\n\
const {target} *relation,\n\
{reference} **out_reference,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
symbols[0],
symbols[1],
reference = reference.as_str(),
);
let mut symbol_index = 3;
for field in model.complete_read().fields() {
let attribute = projected_attribute_model(projection, field.value())?;
match field.multiplicity().container() {
ProjectedContainer::Scalar => {
let accessor = &symbols[symbol_index];
symbol_index += 1;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {accessor}(\n\
const {target} *relation,\n\
{attribute} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
attribute = attribute.target_name().as_str(),
);
}
ProjectedContainer::Sequence => {
let count = &symbols[symbol_index];
let at = &symbols[symbol_index + 1];
symbol_index += 2;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {count}(\n\
const {target} *relation, size_t *out_count,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {at}(\n\
const {target} *relation, size_t index,\n\
{attribute} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
attribute = attribute.target_name().as_str(),
);
}
}
}
for role in model.complete_read().roles().values() {
let union = relation_role_union(model, role.role())?;
match role.multiplicity().container() {
ProjectedContainer::Scalar => {
let accessor = &symbols[symbol_index];
symbol_index += 1;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {accessor}(\n\
const {target} *relation,\n\
{union} **out_player,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
union = union.as_str(),
);
}
ProjectedContainer::Sequence => {
let count = &symbols[symbol_index];
let at = &symbols[symbol_index + 1];
symbol_index += 2;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {count}(\n\
const {target} *relation, size_t *out_count,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n\
type_bridge_status_t TYPE_BRIDGE_CALL {at}(\n\
const {target} *relation, size_t index,\n\
{union} **out_player,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
union = union.as_str(),
);
}
}
}
debug_assert_eq!(symbol_index, symbols.len());
let _ = writeln!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {}({target} **relation);",
symbols[2],
);
Ok(())
}
fn render_model_crud_declarations(
output: &mut String,
model: &ModelProjection,
kind: &str,
) -> Result<(), Diagnostic> {
let Some(create) = model.create().target_name() else {
return Ok(());
};
let target = model.target_name().as_str();
let _ = writeln!(
output,
"\n/* Exact generated-only CRUD for {kind} `{target}`. */"
);
for (scope, owner) in [
("database", "type_bridge_database_t"),
("read_transaction", "type_bridge_read_transaction_t"),
("write_transaction", "type_bridge_write_transaction_t"),
] {
if scope != "read_transaction" {
for operation in ["insert", "put"] {
let symbol = entity_crud_symbol(model, &format!("{scope}_{operation}"))?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {symbol}(\n\
const {owner} *owner,\n\
const {create} *create,\n\
const type_bridge_cancellation_t *cancellation,\n\
{target} **out_entity,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
create = create.as_str(),
);
}
}
let get = entity_crud_symbol(model, &format!("{scope}_get_by_iid"))?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {get}(\n\
const {owner} *owner, type_bridge_byte_view_t iid,\n\
const type_bridge_cancellation_t *cancellation,\n\
{target} **out_entity,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n"
);
if scope != "read_transaction" {
let update = entity_crud_symbol(model, &format!("{scope}_update"))?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {update}(\n\
const {owner} *owner, type_bridge_byte_view_t iid,\n\
const {create} *create,\n\
const type_bridge_cancellation_t *cancellation,\n\
{target} **out_entity,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n",
create = create.as_str(),
);
let delete = entity_crud_symbol(model, &format!("{scope}_delete_by_iid"))?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {delete}(\n\
const {owner} *owner, type_bridge_byte_view_t iid,\n\
const type_bridge_cancellation_t *cancellation,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n"
);
}
let count = entity_crud_symbol(model, &format!("{scope}_count"))?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {count}(\n\
const {owner} *owner,\n\
const type_bridge_cancellation_t *cancellation,\n\
uint64_t *out_count,\n\
type_bridge_execution_diagnostics_t **out_diagnostics);\n"
);
}
Ok(())
}
fn render_entity_model_definitions(
output: &mut String,
projection: &RuntimeProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Entity)
{
render_entity_create_definition(output, projection, model, prefix)?;
render_entity_reference_definitions(output, projection, model, prefix)?;
render_entity_complete_definitions(output, projection, model, prefix)?;
render_model_crud_definitions(output, projection, model, prefix, "entity")?;
}
Ok(())
}
fn render_relation_model_definitions(
output: &mut String,
projection: &RuntimeProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
for model in projection
.models()
.values()
.filter(|model| model.id().kind() == TypeKind::Relation)
{
render_relation_create_definition(output, projection, model, prefix)?;
render_entity_reference_definitions(output, projection, model, prefix)?;
render_relation_complete_definitions(output, projection, model, prefix)?;
render_model_crud_definitions(output, projection, model, prefix, "relation")?;
}
Ok(())
}
fn render_entity_create_definition(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
if !model.create().roles().is_empty() {
return Err(invalid(
"c_emitter_entity_create_has_roles",
"projected C entity construction cannot contain relation roles",
));
}
render_create_definition(output, projection, model, prefix)
}
fn render_relation_create_definition(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
render_create_definition(output, projection, model, prefix)
}
struct CreateSequenceRender<'a> {
chunks: &'a str,
member: &'a str,
token: &'a str,
is_field: bool,
}
fn render_create_graph_metadata(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<Option<(String, usize)>, Diagnostic> {
let Some(table) = create_member_table_symbol(model)? else {
return Ok(None);
};
let args = create_args_type(model)?.expect("create target was checked");
let macro_prefix = prefix.to_ascii_uppercase();
let member_count = model
.create()
.fields()
.len()
.checked_add(model.create().roles().len())
.expect("C create-member count is bounded by the projection ceiling");
let _ = writeln!(
output,
"static const type_bridge_generated_create_member_v1_t {table}[] = {{"
);
for field in model.create().fields() {
let member = entity_field_parameter(model, prefix, field.token())?;
let args_member = match field.multiplicity().container() {
ProjectedContainer::Scalar => member,
ProjectedContainer::Sequence => format!("{member}_chunks"),
};
let kind = match field.multiplicity().container() {
ProjectedContainer::Scalar => "TYPE_BRIDGE_GENERATED_CREATE_MEMBER_VALUE_SCALAR",
ProjectedContainer::Sequence => "TYPE_BRIDGE_GENERATED_CREATE_MEMBER_VALUE_SEQUENCE",
};
let token = field_token_symbol(projection, prefix, model.id(), field.token())?;
let _ = writeln!(
output,
" {{ sizeof(type_bridge_generated_create_member_v1_t),\n\
TYPE_BRIDGE_GENERATED_CREATE_GRAPH_VERSION, {kind}, 0u,\n\
offsetof({args}, {args_member}), &{token},\n\
{{ 0u, 0u, 0u, 0u }} }},"
);
}
for role in model.create().roles().values() {
let member = relation_role_parameter(model, prefix, role.role())?;
let args_member = match role.multiplicity().container() {
ProjectedContainer::Scalar => member,
ProjectedContainer::Sequence => format!("{member}_chunks"),
};
let kind = match role.multiplicity().container() {
ProjectedContainer::Scalar => "TYPE_BRIDGE_GENERATED_CREATE_MEMBER_REFERENCE_SCALAR",
ProjectedContainer::Sequence => {
"TYPE_BRIDGE_GENERATED_CREATE_MEMBER_REFERENCE_SEQUENCE"
}
};
let token = role_token_symbol(projection, prefix, model.id(), role.role())?;
let _ = writeln!(
output,
" {{ sizeof(type_bridge_generated_create_member_v1_t),\n\
TYPE_BRIDGE_GENERATED_CREATE_GRAPH_VERSION, {kind}, 0u,\n\
offsetof({args}, {args_member}), &{token},\n\
{{ 0u, 0u, 0u, 0u }} }},"
);
}
let _ = write!(
output,
"}};\n\
_Static_assert(sizeof({table}) <= {macro_prefix}_HOSTED_OBJECT_BYTES_MIN,\n\
\"generated create-member graph table exceeds the C hosted-object minimum\");\n\
_Static_assert(sizeof({table}) / sizeof({table}[0]) == {member_count}u,\n\
\"generated create-member graph table count drifted\");\n\n"
);
Ok(Some((table, member_count)))
}
fn render_create_sequence_stream(output: &mut String, sequence: &CreateSequenceRender<'_>) {
let chunks = sequence.chunks;
let member = sequence.member;
let token = sequence.token;
let (buffer, cast, values, value_count, references, reference_count) = if sequence.is_field {
(
"value_chunk",
"type_bridge_projected_value_t",
"value_chunk",
"stream_count",
"NULL",
"0u",
)
} else {
(
"reference_chunk",
"type_bridge_projected_reference_t",
"NULL",
"0u",
"reference_chunk",
"stream_count",
)
};
let _ = write!(
output,
" if (args->{member}_chunks != NULL) {{\n\
const {chunks} *chunk = args->{member}_chunks;\n\
stream_count = 0u;\n\
while (chunk != NULL) {{\n\
stream_offset = 0u;\n\
while (stream_offset < chunk->count) {{\n\
copy_count = chunk->count - stream_offset;\n\
if (copy_count > TYPE_BRIDGE_PROJECTED_CREATE_BUILDER_CHUNK_LEN_MAX -\n\
stream_count) {{\n\
copy_count = TYPE_BRIDGE_PROJECTED_CREATE_BUILDER_CHUNK_LEN_MAX -\n\
stream_count;\n\
}}\n\
for (copy_index = 0u; copy_index < copy_count; ++copy_index) {{\n\
{buffer}[stream_count + copy_index] = (const {cast} *)\n\
chunk->values[stream_offset + copy_index];\n\
}}\n\
stream_count += copy_count;\n\
stream_offset += copy_count;\n\
if (stream_count ==\n\
TYPE_BRIDGE_PROJECTED_CREATE_BUILDER_CHUNK_LEN_MAX) {{\n\
status = type_bridge_projected_create_builder_add_v1(\n\
builder, &{token}, {values}, {value_count},\n\
{references}, {reference_count}, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ goto cleanup; }}\n\
stream_count = 0u;\n\
}}\n\
}}\n\
chunk = chunk->next;\n\
}}\n\
if (stream_count != 0u) {{\n\
status = type_bridge_projected_create_builder_add_v1(\n\
builder, &{token}, {values}, {value_count},\n\
{references}, {reference_count}, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ goto cleanup; }}\n\
}}\n\
}}\n"
);
}
fn render_create_definition(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
let Some(target) = model.create().target_name() else {
return Ok(());
};
let [open, close] = entity_create_symbols(model)?.expect("create target was checked");
let args_type = create_args_type(model)?.expect("create target was checked");
let [add_input, preflight] = generated_alias_helper_symbols(prefix)?;
let model_token = model_token_symbol(projection, prefix, model.id())?;
let macro_prefix = prefix.to_ascii_uppercase();
let mut sequences = Vec::new();
for field in model.create().fields() {
if field.multiplicity().container() == ProjectedContainer::Sequence {
let member = entity_field_parameter(model, prefix, field.token())?;
sequences.push((
create_member_sequence_type(model, &member)?,
member,
field_token_symbol(projection, prefix, model.id(), field.token())?,
true,
));
}
}
for role in model.create().roles().values() {
if role.multiplicity().container() == ProjectedContainer::Sequence {
let member = relation_role_parameter(model, prefix, role.role())?;
sequences.push((
create_member_sequence_type(model, &member)?,
member,
role_token_symbol(projection, prefix, model.id(), role.role())?,
false,
));
}
}
let has_fields = !model.create().fields().is_empty();
let has_roles = !model.create().roles().is_empty();
let has_sequences = !sequences.is_empty();
let has_field_sequences = sequences.iter().any(|sequence| sequence.3);
let has_role_sequences = sequences.iter().any(|sequence| !sequence.3);
let create_graph = render_create_graph_metadata(output, projection, model, prefix)?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {open}(\n\
const type_bridge_schema_package_t *package,\n\
const {args_type} *args,\n\
{target} **out_create,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_create_builder_t *builder = NULL;\n\
type_bridge_projected_create_t *generic_create = NULL;\n",
target = target.as_str(),
);
if has_fields {
let value_chunk_len = if has_field_sequences {
"TYPE_BRIDGE_PROJECTED_CREATE_BUILDER_CHUNK_LEN_MAX"
} else {
"1"
};
let _ = writeln!(
output,
" const type_bridge_projected_value_t *value_chunk[{value_chunk_len}];"
);
}
if has_roles {
let reference_chunk_len = if has_role_sequences {
"TYPE_BRIDGE_PROJECTED_CREATE_BUILDER_CHUNK_LEN_MAX"
} else {
"1"
};
let _ = writeln!(
output,
" const type_bridge_projected_reference_t *reference_chunk[{reference_chunk_len}];"
);
}
if create_graph.is_some() {
output.push_str(" type_bridge_generated_create_args_graph_v1_t create_args_graph;\n");
}
output.push_str(
" type_bridge_generated_opaque_input_v1_t alias_inputs[3];\n\
size_t alias_input_count = 0u;\n",
);
if has_sequences {
output.push_str(
" size_t copy_index;\n\
size_t copy_count;\n\
size_t stream_offset;\n\
size_t stream_count;\n",
);
}
output.push_str(" type_bridge_status_t status;\n");
let _ = write!(
output,
" {add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_SCHEMA_PACKAGE, package, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, args, sizeof(*args));\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_create, sizeof(*out_create),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (args == NULL || out_create == NULL || out_diagnostics == NULL) {{\n\
if (out_create != NULL) {{ *out_create = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
if (args->struct_size != sizeof(*args) ||\n\
args->version != {macro_prefix}_CREATE_ARGS_VERSION ||\n\
args->reserved[0] != 0u || args->reserved[1] != 0u ||\n\
args->reserved[2] != 0u || args->reserved[3] != 0u) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n"
);
if let Some((member_table, member_count)) = &create_graph {
let _ = write!(
output,
" create_args_graph.struct_size =\n\
sizeof(type_bridge_generated_create_args_graph_v1_t);\n\
create_args_graph.version =\n\
TYPE_BRIDGE_GENERATED_CREATE_GRAPH_VERSION;\n\
create_args_graph.args = args;\n\
create_args_graph.args_size = sizeof(*args);\n\
create_args_graph.members = {member_table};\n\
create_args_graph.member_count = {member_count}u;\n\
create_args_graph.reserved[0] = 0u;\n\
create_args_graph.reserved[1] = 0u;\n\
create_args_graph.reserved[2] = 0u;\n\
alias_input_count = 0u;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CREATE_ARGS_GRAPH,\n\
&create_args_graph, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_create, sizeof(*out_create),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n"
);
}
let _ = write!(
output,
" *out_create = NULL;\n\
*out_diagnostics = NULL;\n\
status = type_bridge_projected_create_builder_open_v1(\n\
package, &{model_token}, &builder, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ goto cleanup; }}\n"
);
for field in model.create().fields() {
let token = field_token_symbol(projection, prefix, model.id(), field.token())?;
let member = entity_field_parameter(model, prefix, field.token())?;
if field.multiplicity().container() == ProjectedContainer::Scalar {
let _ = write!(
output,
" if (args->{member} != NULL) {{\n\
value_chunk[0] = (const type_bridge_projected_value_t *)args->{member};\n\
status = type_bridge_projected_create_builder_add_v1(\n\
builder, &{token}, value_chunk, 1u, NULL, 0u,\n\
out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ goto cleanup; }}\n\
}}\n"
);
}
}
for role in model.create().roles().values() {
let token = role_token_symbol(projection, prefix, model.id(), role.role())?;
let member = relation_role_parameter(model, prefix, role.role())?;
if role.multiplicity().container() == ProjectedContainer::Scalar {
let _ = write!(
output,
" if (args->{member} != NULL) {{\n\
reference_chunk[0] =\n\
(const type_bridge_projected_reference_t *)args->{member};\n\
status = type_bridge_projected_create_builder_add_v1(\n\
builder, &{token}, NULL, 0u, reference_chunk, 1u,\n\
out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ goto cleanup; }}\n\
}}\n"
);
}
}
for (chunks, member, token, is_field) in &sequences {
render_create_sequence_stream(
output,
&CreateSequenceRender {
chunks,
member,
token,
is_field: *is_field,
},
);
}
let _ = write!(
output,
" status = type_bridge_projected_create_builder_finish(\n\
&builder, &generic_create, out_diagnostics);\n\
(void)type_bridge_projected_create_builder_close(&builder);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
*out_create = ({target} *)generic_create;\n\
return TYPE_BRIDGE_STATUS_OK;\n\
cleanup:\n\
(void)type_bridge_projected_create_builder_close(&builder);\n\
return status;\n\
}}\n\n\
type_bridge_status_t TYPE_BRIDGE_CALL {close}({target} **create) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[1];\n\
size_t alias_input_count = 0u;\n\
type_bridge_projected_create_t *generic_create;\n\
type_bridge_status_t status;\n\
if (create == NULL) {{ return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT; }}\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_CREATE, *create, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
create, sizeof(*create), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
generic_create = (type_bridge_projected_create_t *)*create;\n\
status = type_bridge_projected_create_close(&generic_create);\n\
*create = ({target} *)generic_create;\n\
return status;\n\
}}\n\n",
target = target.as_str(),
);
Ok(())
}
fn render_entity_reference_definitions(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
let Some(target) = model.reference_read().target_name() else {
return Ok(());
};
let symbols = entity_reference_symbols(model, prefix)?;
let model_token = model_token_symbol(projection, prefix, model.id())?;
let [add_input, preflight] = generated_alias_helper_symbols(prefix)?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {}(\n\
const type_bridge_schema_package_t *package,\n\
type_bridge_byte_view_t iid,\n\
{target} **out_reference,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
const type_bridge_projected_reference_descriptor_v1_t descriptor = {{\n\
sizeof(type_bridge_projected_reference_descriptor_v1_t),\n\
TYPE_BRIDGE_PROJECTED_MODEL_INPUT_VERSION, &{model_token}, iid,\n\
NULL, 0u, {{ 0u, 0u, 0u, 0u }}\n\
}};\n\
type_bridge_projected_reference_t *generic_reference = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[3];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_SCHEMA_PACKAGE, package, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, iid.data, iid.length);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_reference, sizeof(*out_reference),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_reference != NULL) {{ *out_reference = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_reference == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_reference_open_v1(\n\
package, &descriptor, &generic_reference, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_reference = ({target} *)generic_reference;\n\
}}\n\
return status;\n\
}}\n\n",
symbols[0],
target = target.as_str(),
);
let mut symbol_index = 3;
for field in model.reference_read().key_fields() {
let constructor = &symbols[symbol_index];
symbol_index += 1;
let projected = model.query_tokens().fields().get(field).ok_or_else(|| {
invalid(
"c_emitter_reference_key_missing",
"projected C reference key is absent from query fields",
)
})?;
let member = projected_member_suffix(prefix, projected.target_name())?;
let attribute_id = attribute_type_id(field)?;
let attribute = projection.models().get(&attribute_id).ok_or_else(|| {
invalid(
"c_emitter_entity_attribute_missing",
"projected C reference key attribute is absent",
)
})?;
let token = field_token_symbol(projection, prefix, model.id(), field)?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {constructor}(\n\
const type_bridge_schema_package_t *package,\n\
const {attribute} *key_{member},\n\
{target} **out_reference,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
const type_bridge_projected_value_t *key_values[1] = {{\n\
(const type_bridge_projected_value_t *)key_{member}\n\
}};\n\
const type_bridge_projected_field_input_v1_t keys[1] = {{\n\
{{ sizeof(type_bridge_projected_field_input_v1_t),\n\
TYPE_BRIDGE_PROJECTED_MODEL_INPUT_VERSION, &{token},\n\
key_values, 1u, {{ 0u, 0u, 0u, 0u }} }}\n\
}};\n\
const type_bridge_projected_reference_descriptor_v1_t descriptor = {{\n\
sizeof(type_bridge_projected_reference_descriptor_v1_t),\n\
TYPE_BRIDGE_PROJECTED_MODEL_INPUT_VERSION, &{model_token},\n\
{{ NULL, 0u }}, keys, 1u, {{ 0u, 0u, 0u, 0u }}\n\
}};\n\
type_bridge_projected_reference_t *generic_reference = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[4];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_SCHEMA_PACKAGE, package, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_VALUE, key_{member}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_reference, sizeof(*out_reference),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_reference != NULL) {{ *out_reference = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_reference == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_reference_open_v1(\n\
package, &descriptor, &generic_reference, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_reference = ({target} *)generic_reference;\n\
}}\n\
return status;\n\
}}\n\n",
target = target.as_str(),
attribute = attribute.target_name().as_str(),
);
}
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {}(\n\
const {target} *reference, type_bridge_byte_view_t *out_iid,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_REFERENCE, reference, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_iid, sizeof(*out_iid),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_iid != NULL) {{\n\
out_iid->data = NULL;\n\
out_iid->length = 0u;\n\
}}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_iid == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_reference_validate_model(\n\
(const type_bridge_projected_reference_t *)reference,\n\
&{model_token}, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
return type_bridge_projected_reference_iid(\n\
(const type_bridge_projected_reference_t *)reference, out_iid);\n\
}}\n\n",
symbols[1],
target = target.as_str(),
);
for field in model.reference_read().key_fields() {
let attribute_id = attribute_type_id(field)?;
let attribute = projection.models().get(&attribute_id).ok_or_else(|| {
invalid(
"c_emitter_entity_attribute_missing",
"projected C reference key attribute is absent",
)
})?;
let token = field_token_symbol(projection, prefix, model.id(), field)?;
let getter = &symbols[symbol_index];
symbol_index += 1;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {getter}(\n\
const {target} *reference,\n\
{attribute} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_value_t *generic_value = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_REFERENCE, reference, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_value, sizeof(*out_value),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_value != NULL) {{ *out_value = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_value == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_reference_key(\n\
(const type_bridge_projected_reference_t *)reference, &{token},\n\
&generic_value, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_value = ({attribute} *)generic_value;\n\
}}\n\
return status;\n\
}}\n\n",
target = target.as_str(),
attribute = attribute.target_name().as_str(),
);
}
let close = &symbols[2];
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {close}({target} **reference) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[1];\n\
size_t alias_input_count = 0u;\n\
type_bridge_projected_reference_t *generic_reference;\n\
type_bridge_status_t status;\n\
if (reference == NULL) {{ return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT; }}\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_REFERENCE, *reference, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
reference, sizeof(*reference), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
generic_reference = (type_bridge_projected_reference_t *)*reference;\n\
status = type_bridge_projected_reference_close(&generic_reference);\n\
*reference = ({target} *)generic_reference;\n\
return status;\n\
}}\n\n",
target = target.as_str(),
);
Ok(())
}
fn render_entity_complete_definitions(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
let target = model.target_name().as_str();
let reference = model.reference_read().target_name().ok_or_else(|| {
invalid(
"c_emitter_entity_reference_missing",
"projected C entity must expose a nominal reference",
)
})?;
let symbols = entity_complete_symbols(model, prefix)?;
let model_token = model_token_symbol(projection, prefix, model.id())?;
let [add_input, preflight] = generated_alias_helper_symbols(prefix)?;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {}(\n\
const {target} *entity, type_bridge_byte_view_t *out_iid,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_THING, entity, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_iid, sizeof(*out_iid),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_iid != NULL) {{\n\
out_iid->data = NULL;\n\
out_iid->length = 0u;\n\
}}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_iid == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_thing_validate_model(\n\
(const type_bridge_projected_thing_t *)entity,\n\
&{model_token}, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
return type_bridge_projected_thing_iid(\n\
(const type_bridge_projected_thing_t *)entity, out_iid);\n\
}}\n\n\
type_bridge_status_t TYPE_BRIDGE_CALL {}(\n\
const {target} *entity,\n\
{reference} **out_reference,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_reference_t *generic_reference = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_THING, entity, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_reference, sizeof(*out_reference),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_reference != NULL) {{ *out_reference = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_reference == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_thing_validate_model(\n\
(const type_bridge_projected_thing_t *)entity,\n\
&{model_token}, out_diagnostics);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
status = type_bridge_projected_thing_reference(\n\
(const type_bridge_projected_thing_t *)entity,\n\
&generic_reference, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_reference = ({reference} *)generic_reference;\n\
}}\n\
return status;\n\
}}\n\n",
symbols[0],
symbols[1],
reference = reference.as_str(),
);
let mut symbol_index = 3;
for field in model.complete_read().fields() {
let attribute = projected_attribute_model(projection, field.value())?;
let token = field_token_symbol(projection, prefix, model.id(), field.token())?;
match field.multiplicity().container() {
ProjectedContainer::Scalar => {
let accessor = &symbols[symbol_index];
symbol_index += 1;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {accessor}(\n\
const {target} *entity,\n\
{attribute} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_value_t *generic_value = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_THING, entity, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_value, sizeof(*out_value),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_value != NULL) {{ *out_value = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_value == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_thing_scalar_field_value(\n\
(const type_bridge_projected_thing_t *)entity, &{token},\n\
&generic_value, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_value = ({attribute} *)generic_value;\n\
}}\n\
return status;\n\
}}\n\n",
attribute = attribute.target_name().as_str(),
);
}
ProjectedContainer::Sequence => {
let count = &symbols[symbol_index];
let at = &symbols[symbol_index + 1];
symbol_index += 2;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {count}(\n\
const {target} *entity, size_t *out_count,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_THING, entity, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_count, sizeof(*out_count),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_count != NULL) {{ *out_count = 0u; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_count == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
return type_bridge_projected_thing_field_count(\n\
(const type_bridge_projected_thing_t *)entity, &{token},\n\
out_count, out_diagnostics);\n\
}}\n\n\
type_bridge_status_t TYPE_BRIDGE_CALL {at}(\n\
const {target} *entity, size_t index,\n\
{attribute} **out_value,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_value_t *generic_value = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_THING, entity, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_value, sizeof(*out_value),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_value != NULL) {{ *out_value = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_value == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_thing_field_value_at(\n\
(const type_bridge_projected_thing_t *)entity, &{token}, index,\n\
&generic_value, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_value = ({attribute} *)generic_value;\n\
}}\n\
return status;\n\
}}\n\n",
attribute = attribute.target_name().as_str(),
);
}
}
}
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {}({target} **entity) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[1];\n\
size_t alias_input_count = 0u;\n\
type_bridge_projected_thing_t *generic_entity;\n\
type_bridge_status_t status;\n\
if (entity == NULL) {{ return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT; }}\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_THING, *entity, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
entity, sizeof(*entity), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
generic_entity = (type_bridge_projected_thing_t *)*entity;\n\
status = type_bridge_projected_thing_close(&generic_entity);\n\
*entity = ({target} *)generic_entity;\n\
return status;\n\
}}\n\n",
symbols[2],
);
render_complete_role_definitions(
output,
projection,
model,
prefix,
&symbols,
&mut symbol_index,
&add_input,
&preflight,
)?;
debug_assert_eq!(symbol_index, symbols.len());
Ok(())
}
#[allow(clippy::too_many_arguments)]
fn render_complete_role_definitions(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
symbols: &[String],
symbol_index: &mut usize,
add_input: &str,
preflight: &str,
) -> Result<(), Diagnostic> {
let target = model.target_name().as_str();
for role in model.complete_read().roles().values() {
let token = role_token_symbol(projection, prefix, model.id(), role.role())?;
let union = relation_role_union(model, role.role())?.as_str();
match role.multiplicity().container() {
ProjectedContainer::Scalar => {
let accessor = &symbols[*symbol_index];
*symbol_index += 1;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {accessor}(\n\
const {target} *entity,\n\
{union} **out_player,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_reference_t *generic_reference = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_THING, entity, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_player, sizeof(*out_player),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_player != NULL) {{ *out_player = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_player == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_thing_scalar_role_reference(\n\
(const type_bridge_projected_thing_t *)entity, &{token},\n\
&generic_reference, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK && generic_reference != NULL) {{\n\
status = type_bridge_projected_reference_validate_role(\n\
generic_reference, &{token}, out_diagnostics);\n\
}}\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_player = ({union} *)generic_reference;\n\
}} else if (generic_reference != NULL) {{\n\
(void)type_bridge_projected_reference_close(&generic_reference);\n\
}}\n\
return status;\n\
}}\n\n"
);
}
ProjectedContainer::Sequence => {
let count = &symbols[*symbol_index];
let at = &symbols[*symbol_index + 1];
*symbol_index += 2;
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {count}(\n\
const {target} *entity, size_t *out_count,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_THING, entity, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_count, sizeof(*out_count),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_count != NULL) {{ *out_count = 0u; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_count == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
return type_bridge_projected_thing_role_count(\n\
(const type_bridge_projected_thing_t *)entity, &{token},\n\
out_count, out_diagnostics);\n\
}}\n\n\
type_bridge_status_t TYPE_BRIDGE_CALL {at}(\n\
const {target} *entity, size_t index,\n\
{union} **out_player,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_reference_t *generic_reference = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[2];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_THING, entity, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{token}, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_player, sizeof(*out_player),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_player != NULL) {{ *out_player = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_player == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = type_bridge_projected_thing_role_reference_at(\n\
(const type_bridge_projected_thing_t *)entity, &{token}, index,\n\
&generic_reference, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
status = type_bridge_projected_reference_validate_role(\n\
generic_reference, &{token}, out_diagnostics);\n\
}}\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_player = ({union} *)generic_reference;\n\
}} else if (generic_reference != NULL) {{\n\
(void)type_bridge_projected_reference_close(&generic_reference);\n\
}}\n\
return status;\n\
}}\n\n"
);
}
}
}
Ok(())
}
fn render_relation_complete_definitions(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
) -> Result<(), Diagnostic> {
render_entity_complete_definitions(output, projection, model, prefix)
}
fn render_model_crud_definitions(
output: &mut String,
projection: &RuntimeProjection,
model: &ModelProjection,
prefix: &str,
kind: &str,
) -> Result<(), Diagnostic> {
let Some(create) = model.create().target_name() else {
return Ok(());
};
let target = model.target_name().as_str();
let model_token = model_token_symbol(projection, prefix, model.id())?;
let [add_input, preflight] = generated_alias_helper_symbols(prefix)?;
for (scope, owner) in [
("database", "type_bridge_database_t"),
("read_transaction", "type_bridge_read_transaction_t"),
("write_transaction", "type_bridge_write_transaction_t"),
] {
let owner_kind = match scope {
"database" => "TYPE_BRIDGE_GENERATED_INPUT_DATABASE",
"read_transaction" => "TYPE_BRIDGE_GENERATED_INPUT_READ_TRANSACTION",
"write_transaction" => "TYPE_BRIDGE_GENERATED_INPUT_WRITE_TRANSACTION",
_ => unreachable!(),
};
if scope != "read_transaction" {
for operation in ["insert", "put"] {
let symbol = entity_crud_symbol(model, &format!("{scope}_{operation}"))?;
let runtime = format!("type_bridge_{scope}_{kind}_{operation}");
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {symbol}(\n\
const {owner} *owner,\n\
const {create} *create,\n\
const type_bridge_cancellation_t *cancellation,\n\
{target} **out_entity,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_thing_t *generic_entity = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[4];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
{owner_kind}, owner, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_CREATE, create, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_entity, sizeof(*out_entity),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_entity != NULL) {{ *out_entity = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_entity == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = {runtime}(owner, &{model_token},\n\
(const type_bridge_projected_create_t *)create, cancellation,\n\
&generic_entity, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_entity = ({target} *)generic_entity;\n\
}}\n\
return status;\n\
}}\n\n",
create = create.as_str(),
);
}
}
let get = entity_crud_symbol(model, &format!("{scope}_get_by_iid"))?;
let runtime_get = format!("type_bridge_{scope}_{kind}_get_by_iid");
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {get}(\n\
const {owner} *owner, type_bridge_byte_view_t iid,\n\
const type_bridge_cancellation_t *cancellation,\n\
{target} **out_entity,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_thing_t *generic_entity = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[4];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
{owner_kind}, owner, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, iid.data, iid.length);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_entity, sizeof(*out_entity),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_entity != NULL) {{ *out_entity = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_entity == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = {runtime_get}(owner, &{model_token}, iid, cancellation,\n\
&generic_entity, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_entity = ({target} *)generic_entity;\n\
}}\n\
return status;\n\
}}\n\n"
);
if scope != "read_transaction" {
let update = entity_crud_symbol(model, &format!("{scope}_update"))?;
let runtime_update = format!("type_bridge_{scope}_{kind}_update");
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {update}(\n\
const {owner} *owner, type_bridge_byte_view_t iid,\n\
const {create} *create,\n\
const type_bridge_cancellation_t *cancellation,\n\
{target} **out_entity,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_projected_thing_t *generic_entity = NULL;\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[5];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
{owner_kind}, owner, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, iid.data, iid.length);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_CREATE, create, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_entity, sizeof(*out_entity),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_entity != NULL) {{ *out_entity = NULL; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_entity == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
status = {runtime_update}(owner, &{model_token}, iid,\n\
(const type_bridge_projected_create_t *)create, cancellation,\n\
&generic_entity, out_diagnostics);\n\
if (status == TYPE_BRIDGE_STATUS_OK) {{\n\
*out_entity = ({target} *)generic_entity;\n\
}}\n\
return status;\n\
}}\n\n",
create = create.as_str(),
);
let delete = entity_crud_symbol(model, &format!("{scope}_delete_by_iid"))?;
let runtime_delete = format!("type_bridge_{scope}_{kind}_delete_by_iid");
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {delete}(\n\
const {owner} *owner, type_bridge_byte_view_t iid,\n\
const type_bridge_cancellation_t *cancellation,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[4];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
{owner_kind}, owner, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_BYTES, iid.data, iid.length);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_diagnostics, sizeof(*out_diagnostics), NULL, 0u);\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
*out_diagnostics = NULL;\n\
return {runtime_delete}(\n\
owner, &{model_token}, iid, cancellation, out_diagnostics);\n\
}}\n\n"
);
}
let count = entity_crud_symbol(model, &format!("{scope}_count"))?;
let runtime_count = format!("type_bridge_{scope}_{kind}_count");
let _ = write!(
output,
"type_bridge_status_t TYPE_BRIDGE_CALL {count}(\n\
const {owner} *owner,\n\
const type_bridge_cancellation_t *cancellation,\n\
uint64_t *out_count,\n\
type_bridge_execution_diagnostics_t **out_diagnostics) {{\n\
type_bridge_generated_opaque_input_v1_t alias_inputs[3];\n\
size_t alias_input_count = 0u;\n\
type_bridge_status_t status;\n\
{add_input}(alias_inputs, &alias_input_count,\n\
{owner_kind}, owner, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_PROJECTED_TOKEN, &{model_token}, 1u);\n\
{add_input}(alias_inputs, &alias_input_count,\n\
TYPE_BRIDGE_GENERATED_INPUT_CANCELLATION, cancellation, 1u);\n\
status = {preflight}(alias_inputs, alias_input_count,\n\
out_count, sizeof(*out_count),\n\
out_diagnostics, sizeof(*out_diagnostics));\n\
if (status != TYPE_BRIDGE_STATUS_OK) {{ return status; }}\n\
if (out_count != NULL) {{ *out_count = 0u; }}\n\
if (out_diagnostics != NULL) {{ *out_diagnostics = NULL; }}\n\
if (out_count == NULL || out_diagnostics == NULL) {{\n\
return TYPE_BRIDGE_STATUS_INVALID_ARGUMENT;\n\
}}\n\
return {runtime_count}(\n\
owner, &{model_token}, cancellation, out_count, out_diagnostics);\n\
}}\n\n"
);
}
Ok(())
}
fn render_chunked_byte_view(output: &mut String, name: &str, bytes: &[u8]) {
assert!(
!bytes.is_empty(),
"canonical generated package resources are nonempty"
);
for (chunk_index, byte_chunk) in bytes.chunks(C_EMBEDDED_BYTE_CHUNK_MAX).enumerate() {
let _ = writeln!(
output,
"static const uint8_t {name}_chunk_{chunk_index}[] = {{"
);
for line in byte_chunk.chunks(12) {
output.push_str(" ");
for byte in line {
let _ = write!(output, "0x{byte:02x}u, ");
}
output.push('\n');
}
let _ = write!(
output,
"}};\n\
_Static_assert(sizeof({name}_chunk_{chunk_index}) <=\n\
{C_EMBEDDED_BYTE_CHUNK_MAX}u,\n\
\"generated embedded byte chunk exceeds its portable ceiling\");\n\n"
);
}
let _ = writeln!(
output,
"static const type_bridge_byte_view_t {name}_chunks[] = {{"
);
for chunk_index in 0..bytes.len().div_ceil(C_EMBEDDED_BYTE_CHUNK_MAX) {
let _ = writeln!(
output,
" {{ {name}_chunk_{chunk_index}, sizeof({name}_chunk_{chunk_index}) }},"
);
}
let _ = write!(
output,
"}};\n\
_Static_assert(sizeof({name}_chunks) <= {C_HOSTED_OBJECT_BYTES_MIN}u,\n\
\"generated embedded chunk table exceeds the C hosted-object minimum\");\n\n"
);
}
fn chunked_byte_view_initializer(name: &str, total_length: usize) -> String {
format!(
"{{ sizeof(type_bridge_chunked_byte_view_v1_t), \
TYPE_BRIDGE_CHUNKED_BYTE_VIEW_VERSION, {name}_chunks, \
sizeof({name}_chunks) / sizeof({name}_chunks[0]), {total_length}u, \
{{ 0u, 0u, 0u, 0u }} }}"
)
}
#[cfg(test)]
mod tests {
use super::{
C_RUNTIME_HEADER_EXTERNAL_IDENTIFIER_COUNT, C_RUNTIME_HEADER_MACRO_IDENTIFIER_COUNT,
C_SIMULTANEOUS_MACRO_MAX, C_SUPPORTED_IMPLEMENTATION_MACRO_RESERVE,
C_TRANSLATION_UNIT_IDENTIFIER_MAX, validate_c_translation_inventory,
};
#[test]
fn runtime_inventory_matches_the_current_header_and_contract() {
let header = include_str!("../../../c/include/typebridge/type_bridge.h");
let contract: serde_json::Value =
serde_json::from_str(include_str!("../../../../../tests/contracts/c-abi.json"))
.expect("C ABI inventory parses");
let macros = header
.lines()
.filter_map(|line| line.strip_prefix("#define "))
.filter_map(|definition| definition.split_ascii_whitespace().next())
.map(|name| name.split_once('(').map_or(name, |(name, _)| name))
.collect::<std::collections::BTreeSet<_>>();
assert_eq!(macros.len(), C_RUNTIME_HEADER_MACRO_IDENTIFIER_COUNT);
assert_eq!(
header
.lines()
.filter(|line| line.starts_with("TYPE_BRIDGE_API"))
.count(),
C_RUNTIME_HEADER_EXTERNAL_IDENTIFIER_COUNT
);
let exports = contract["exports"]
.as_array()
.expect("C exports form an array");
assert_eq!(exports.len(), C_RUNTIME_HEADER_EXTERNAL_IDENTIFIER_COUNT);
for name in exports {
assert!(header.contains(&format!("{}(", name.as_str().expect("export name is text"))));
}
}
#[test]
fn translation_identifier_limit_accepts_the_boundary_and_rejects_one_more() {
let exact = C_TRANSLATION_UNIT_IDENTIFIER_MAX - C_RUNTIME_HEADER_EXTERNAL_IDENTIFIER_COUNT;
validate_c_translation_inventory(exact, 0).expect("exact identifier limit is accepted");
let error = validate_c_translation_inventory(exact + 1, 0)
.expect_err("excess identifier is rejected");
assert_eq!(
error.code().as_str(),
"c_emitter_translation_unit_identifier_limit_exceeded"
);
}
#[test]
fn translation_macro_limit_accepts_the_boundary_and_rejects_one_more() {
let exact = C_SIMULTANEOUS_MACRO_MAX
- C_RUNTIME_HEADER_MACRO_IDENTIFIER_COUNT
- C_SUPPORTED_IMPLEMENTATION_MACRO_RESERVE;
validate_c_translation_inventory(0, exact).expect("exact macro limit is accepted");
let error =
validate_c_translation_inventory(0, exact + 1).expect_err("excess macro is rejected");
assert_eq!(
error.code().as_str(),
"c_emitter_simultaneous_macro_limit_exceeded"
);
}
}