mutating func readBlock()

in Sources/TSCUtility/BitstreamReader.swift [278:338]


  mutating func readBlock<Visitor: BitstreamVisitor>(id: UInt64, abbrevWidth: Int, abbrevInfo: [Bitstream.Abbreviation], visitor: inout Visitor) throws {
    var abbrevInfo = abbrevInfo

    while !cursor.isAtEnd {
      switch try cursor.read(abbrevWidth) {
      case Bitstream.AbbreviationID.endBlock.rawValue:
        try cursor.advance(toBitAlignment: 32)
        // FIXME: check expected length
        try visitor.didExitBlock()
        return

      case Bitstream.AbbreviationID.enterSubblock.rawValue:
        let blockID = try cursor.readVBR(8)
        let newAbbrevWidth = Int(try cursor.readVBR(4))
        try cursor.advance(toBitAlignment: 32)
        let blockLength = try cursor.read(32) * 4

        switch blockID {
        case 0:
          try readBlockInfoBlock(abbrevWidth: newAbbrevWidth)
        case 1...7:
          // Metadata blocks we don't understand yet
          fallthrough
        default:
          guard try visitor.shouldEnterBlock(id: blockID) else {
            try cursor.skip(bytes: Int(blockLength))
            break
          }
          try readBlock(
            id: blockID, abbrevWidth: newAbbrevWidth,
            abbrevInfo: globalAbbrevs[blockID] ?? [], visitor: &visitor)
        }

      case Bitstream.AbbreviationID.defineAbbreviation.rawValue:
        let numOps = Int(try cursor.readVBR(5))
        abbrevInfo.append(try readAbbrev(numOps: numOps))

      case Bitstream.AbbreviationID.unabbreviatedRecord.rawValue:
        let code = try cursor.readVBR(6)
        let numOps = try cursor.readVBR(6)
        let operands = UnsafeMutableBufferPointer<UInt64>.allocate(capacity: Int(numOps))
        defer { operands.deallocate() }
        for i in 0..<Int(numOps) {
          operands[i] = try cursor.readVBR(6)
        }
        try visitor.visit(record: .init(id: code, fields: UnsafeBufferPointer(operands), payload: .none))

      case let abbrevID:
        guard Int(abbrevID) - 4 < abbrevInfo.count else {
          throw Error.noSuchAbbrev(blockID: id, abbrevID: Int(abbrevID))
        }
        try withAbbreviatedRecord(abbrevInfo[Int(abbrevID) - 4]) { record in
          try visitor.visit(record: record)
        }
      }
    }

    guard id == Self.fakeTopLevelBlockID else {
      throw Error.missingEndBlock(blockID: id)
    }
  }