Skip to content

Support variable-length structs as array elements#109

Draft
Copilot wants to merge 3 commits intomasterfrom
copilot/support-variable-length-structs
Draft

Support variable-length structs as array elements#109
Copilot wants to merge 3 commits intomasterfrom
copilot/support-variable-length-structs

Conversation

Copy link

Copilot AI commented Dec 6, 2025

Emboss currently rejects arrays with variable-length struct elements, even when the element count is explicitly specified. This prevents defining common packet formats like Bluetooth batch scan results where variable-length records are packed in an array.

Changes

Frontend constraint relaxation (constraints.py):

  • Allow variable-sized elements when array has explicit count (Bar[n])
  • Reject only when using automatic sizing (Bar[]) since element size is needed to compute count

New runtime view (emboss_array_view.h):

  • Added GenericDynamicSizeArrayView that computes element offsets at runtime by iterating previous elements' SizeInBytes()
  • Supports standard view operations: operator[], ElementCount(), Ok(), Equals()

Code generator (header_generator.py):

  • Emit GenericDynamicSizeArrayView when element size is not compile-time constant
  • Removed dead _get_type_size function

Example

struct DynamicRecord:
  0 [+1]      UInt      data_len (n)
  1 [+n]      UInt:8[]  data

struct Container:
  0 [+1]   UInt                 num_records (r)
  1 [+99]  DynamicRecord[r]     records  # Now allowed
auto view = MakeContainerView(&buffer);
for (size_t i = 0; i < view.records().ElementCount(); ++i) {
    auto record = view.records()[i];
    // Access variable-length record fields
}

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • www.googleapis.com
    • Triggering command: /usr/local/lib/node_modules/@bazel/bazelisk/bazelisk-linux_amd64 /usr/local/lib/node_modules/@bazel/bazelisk/bazelisk-linux_amd64 version (dns block)
    • Triggering command: /usr/local/lib/node_modules/@bazel/bazelisk/bazelisk-linux_amd64 /usr/local/lib/node_modules/@bazel/bazelisk/bazelisk-linux_amd64 test //compiler/front_end:constraints_test --test_output=errors (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Support variable length structs as array elements</issue_title>
<issue_description>This issue was copied from the upstream repository google/emboss.

Original issue: google#230
Original state: open, created at: 2025-09-17T22:56:20Z, updated at: 2025-09-17T22:56:20Z, by @fsareshwala


Original description

I was trying to define a set of emboss structs from the batch scanning section of Android's Bluetooth vendor extensions. In the full version of the results that the Controller returns, there are some variable length array elements that are currently impossible to add to Emboss. I would have liked to do something like this:

struct LEBatchScanTruncatedResult:
  0     [+hci.BdAddr.$size_in_bytes]  hci.BdAddr         peer_address
  $next [+1]                          hci.LEAddressType  peer_address_type
  $next [+1]                          Int                tx_power
  $next [+1]                          Int                rssi
  $next [+2]                          UInt               timestamp

struct LEBatchScanFullResult:
  0     [+hci.BdAddr.$size_in_bytes]  hci.BdAddr         peer_address
  $next [+1]                          hci.LEAddressType  peer_address_type
  $next [+1]                          Int                tx_power
  $next [+1]                          Int                rssi
  $next [+2]                          UInt               timestamp
  $next [+1]                          UInt               advertising_data_length (ad_len)
  $next [+ad_len]                     UInt:8[ad_len]     advertising_data
  $next [+1]                          UInt               scan_response_length (sr_len)
  $next [+sr_len]                     UInt:8[sr_len]     scan_response_data

struct LEBatchScanReadResultsCommandCompleteEvent:
  let hdr_size = hci.CommandCompleteEvent.$size_in_bytes
  0     [+hdr_size]                                     hci.CommandCompleteEvent                 command_complete
  $next [+1]                                            hci.StatusCode                           status
  $next [+1]                                            BatchScanSubOpcode                       sub_opcode
    [requires: this == BatchScanSubOpcode.READ_RESULT_PARAMETERS]

  $next [+1]                                            BatchScanReadMode                        read_mode
  $next [+1]                                            UInt                                     num_records
  if read_mode == BatchScanReadMode.TRUNCATED_MODE:
    $next [+LEBatchScanTruncatedResult.$size_in_bytes]  LEBatchScanTruncatedResult[num_records]  truncated_results

  if read_mode == BatchScanReadMode.FULL_MODE:
    let remaining = command_complete.return_parameters_size-hdr_size-4
    $next [+remaining]                                  LEBatchScanFullResult[num_records]       full_results

Unfortunately, this results in an error from Emboss: "error: Array elements must be fixed size." We should figure out a way to add such functionality in so that users don't have to awkwardly break up packets into multiple structs.</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 2 commits December 6, 2025 03:08
- Modified constraint check in constraints.py to allow dynamic-sized array
  elements when element count is explicit (not automatic)
- Added GenericDynamicSizeArrayView C++ template to emboss_array_view.h
- Updated header_generator.py to emit GenericDynamicSizeArrayView for arrays
  with variable-sized elements
- Added dynamic_size_array_view_adapter template to generated_code_templates

Co-authored-by: AaronWebster <3766083+AaronWebster@users.noreply.github.com>
- Fix potential underflow in ConstructElementAtOffsetHelper by checking offset
  before computing remaining bytes
- Add documentation for required ElementView interface (SizeInBytes, SizeIsKnown, Ok)
- Remove unused _get_type_size function from header_generator.py

Co-authored-by: AaronWebster <3766083+AaronWebster@users.noreply.github.com>
Copilot AI changed the title [WIP] Support variable length structs as array elements Support variable-length structs as array elements Dec 6, 2025
Copilot AI requested a review from AaronWebster December 6, 2025 03:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support variable length structs as array elements

2 participants