subFieldDescriptorsForType static method

List<({String expectedName, String fieldLabel, int startBit, Map<String, Object?>? subLogicType, int width})> subFieldDescriptorsForType(
  1. Map<String, Object?> logicType,
  2. String parentName
)

Compute sub-field descriptors for an arbitrary logicType map.

parentName is used to derive expected signal names. This is static so it can be called recursively for nested arrays without needing a full SignalOccurrence.

Implementation

static List<
    ({
      String expectedName,
      String fieldLabel,
      int width,
      int startBit,
      Map<String, Object?>? subLogicType,
    })> subFieldDescriptorsForType(
  Map<String, Object?> logicType,
  String parentName,
) {
  final fields = logicType['fields'] as List<dynamic>?;
  if (fields != null) {
    return fields.map((f) {
      final field = f as Map<String, dynamic>;
      final fieldName = field['name'] as String? ?? '?';
      final width = field['width'] as int? ?? 1;
      final bits = field['bits'] as List<dynamic>?;
      final startBit = bits != null && bits.isNotEmpty
          ? (bits.cast<int>().reduce((a, b) => a < b ? a : b))
          : 0;
      // Naming convention: Sanitizer.sanitizeSV("$parentName.$fieldName")
      // which produces "$parentName_$fieldName"
      final expectedName = '${parentName}_$fieldName';
      return (
        expectedName: expectedName,
        fieldLabel: fieldName,
        width: width,
        startBit: startBit,
        subLogicType: field['type'] as Map<String, Object?>?,
      );
    }).toList();
  }

  final arrayDims = logicType['arrayDims'] as List<dynamic>?;
  if (arrayDims != null && arrayDims.isNotEmpty) {
    final leafWidth = (logicType['elementWidth'] as int?) ?? 1;
    final outerDim = arrayDims.first as int;
    // For multi-dimensional arrays, each outer element spans all
    // remaining dimensions times the leaf element width.
    final remainingDims =
        arrayDims.length > 1 ? arrayDims.sublist(1).cast<int>() : <int>[];
    final elementWidth = remainingDims.isEmpty
        ? leafWidth
        : remainingDims.fold<int>(leafWidth, (acc, d) => acc * d);

    // Build sub-logicType for remaining dimensions (if any).
    final subLogicType = remainingDims.isEmpty
        ? null
        : <String, Object?>{
            'width': elementWidth,
            'arrayDims': remainingDims,
            'elementWidth': leafWidth,
          };

    return List.generate(outerDim, (i) {
      // Naming convention: Sanitizer.sanitizeSV("$parentName[$i]")
      // which produces "$parentName_${i}_"
      final expectedName = '${parentName}_${i}_';
      return (
        expectedName: expectedName,
        fieldLabel: '[$i]',
        width: elementWidth,
        startBit: i * elementWidth,
        subLogicType: subLogicType,
      );
    });
  }

  return const [];
}