--- state: beta description: Mask fields in a thrift struct --- # FieldMask ## Overview Field Mask is a data structure that represents a subset of fields and nested fields of a thrift struct, with utilities to manipulate these fields (e.g., copy certain fields from one thrift object to another). ## Motivation When a client doesn't need all fields, the server can only return selected fields to the client to reduce network bandwidth. ## Data Structure Field Mask can be either an inclusive mask or an exclusive mask — fields or nested field masks that are included or excluded. The nested masks are used for masking the nested fields. (Actual definition can be found here: [`thrift/lib/thrift/field_mask.thrift`](https://github.com/facebook/fbthrift/blob/main/thrift/lib/thrift/field_mask.thrift). ``` union Mask { 1: map excludes; // Fields that will be excluded 2: map includes; // Fields that will be included } const Mask allMask = {"excludes": {}}; // Masks all fields/whole field. const Mask noneMask = {"includes": {}}; // Masks no fields.` ``` [Debug protocol](/features/serialization/protocols.md#debug-protocol) can be used to convert Mask to a human readable string. ## APIs Currently it provides the following APIs (APIs are in [`thrift/lib/cpp2/protocol/FieldMask.h`](https://github.com/facebook/fbthrift/blob/main/thrift/lib/cpp2/protocol/FieldMask.h)). These APIs are available for both schemaful (ThriftStruct) and schemaless (protocol::Object) Thrift structs. [Package](../idl/#package-declaration) name must be defined in Thrift file to use field mask APIs. It will give a compile-error without a package name. ```cpp // Whether field mask is compatible with thrift struct (the masked fields exist // in ThriftStruct) bool is_compatible_with(Mask); // Call field_ref().ensure() for all masked fields and their precedents void ensure(Mask, ThriftStruct); // Remove all masked fields void clear(Mask, ThriftStruct); // Copy masked fields from src to dst. If some masked fields are not set in src, // remove them in dst as well. void copy(Mask, ThriftStruct src, ThriftStruct dst); // It also provides support for protocol::Object void clear(Mask, protocol::Object); void copy(Mask, protocol::Object src, protocol::Object dst); ``` ## MaskBuilder MaskBuilder is a wrapper for Mask that works as a strongly typed mask. It is tied to a specific thrift struct type, and it provides APIs to add fields to the Mask with field names and field identifiers like idents. ``` struct MaskBuilder { // All methods for constructing Mask return itself to chain MaskBuilder& reset_to_none(); MaskBuilder& reset_to_all(); MaskBuilder& invert(); Mask& toThrift(); // includes and excludes with field names and all ids MaskBuilder& includes(list fieldNames, const Mask& mask = allMask()); MaskBuilder& excludes(list fieldNames, const Mask& mask = allMask()); // Id can be Ordinal, FieldId, Ident, TypeTag, FieldTag MaskBuilder& includes(const Mask& mask = allMask()); MaskBuilder& excludes(const Mask& mask = allMask()); // reset_and_includes calls reset_to_none() and includes() // reset_and_excludes calls reset_to_all() and excludes() // Mask APIs void ensure(Struct& obj) const; void clear(Struct& obj) const; void copy(const Struct& src, Struct& dst) const; } ``` It also provides `MaskAdapter`, which adapts `Mask` to be `MaskBuilder` in a thrift struct. ## Logical operators These are logical operators to construct a new mask. ``` Mask operator&(const Mask&, const Mask&); // intersect Mask operator|(const Mask&, const Mask&); // union Mask operator-(const Mask&, const Mask&); // subtract ``` ## Compare Constructs a FieldMask object that includes the fields that are different in the given two Thrift structs. ``` Mask compare(const Struct& original, const Struct& modified); ``` ## Serialization with Mask Mask can be used with parseObject to construct a partial protocol::Object with only the masked fields. This also returns MaskedProtocolData, which stores the serialized data of the other fields, and serializeObject with MaskedProtocolData reserializes the object. ``` struct MaskedDecodeResult { Object included; MaskedProtocolData excluded; }; // Only parses values that are masked. Unmasked fields are stored in MaskedProtocolData. MaskedDecodeResult parseObject(const folly::IOBuf& buf, Mask mask); // serialize the fields from the Object and MaskedProtocolData std::unique_ptr serializeObject(const protocol::Object& obj, MaskedProtocolData& protocolData); ``` This is useful when updating a small part of the object from serialized data, as it doesn’t need to deserialize the entire object. The function applyPatchToSerializedData performs this by extracting a mask from patch with only the updated fields. ``` std::unique_ptr applyPatchToSerializedData( const protocol::Object& patch, const folly::IOBuf& buf); ```