     return result
   }
 
-  /// Read the number of fields in an object or the binary length of a scalar
-  /// field.
-  ///
-  /// - Returns: The read value
-  private func readFieldLength() -> Int {
-    return Int(UInt32(littleEndian: readRaw(UInt32.self)))
+  private func readFieldLength() -> (isObject: Bool, length: Int) {
+    let raw = UInt32(littleEndian: readRaw(UInt32.self))
+    let isObject = (raw & (UInt32(1) << 31)) != 0
+    let length = Int(raw & ~(UInt32(1) << 31))
+    return (isObject, length)
+  }
+
+
+  /// Read the number of fields in an object.
+  ///
+  /// - Returns: The number of fields in the following object
+  private func readObjectLength() -> Int {
+    let (isObject, length) = readFieldLength()
+    assert(isObject)
+    return length
+  }
+
+  /// Read the size of a scalar in bytes
+  ///
+  /// - Returns: The size of the following scalar in bytes
+  private func readScalarLength() -> Int {
+    let (isObject, length) = readFieldLength()
+    assert(!isObject)
+    return length
   }
 
   /// Read the protocol version and validate that it can be read using the given

  fileprivate func read<T: ByteTreeScalarDecodable>(
    _ scalarType: T.Type
  ) -> T {
    let fieldSize = readFieldLength()
    defer {
      pointer = pointer.advanced(by: fieldSize)
    }

  fileprivate func read<T: ByteTreeObjectDecodable>(
    _ objectType: T.Type
  ) -> T {
    let numFields = readObjectLength()
    let objectReader = ByteTreeObjectReader(reader: self,
                                            numFields: numFields)
    return T.read(from: objectReader, numFields: numFields, userInfo: userInfo)
