void OnTagChanged(int oldValue, int newValue, SerializedProperty property)
        {
            Asset asset       = property?.serializedObject.targetObject as Asset;
            int   metricIndex = GetMetricIndex(property);
            int   change      = oldValue ^ newValue;

            List <Type> tagTypes = TagAttribute.GetVisibleTypesInInspector().ToList();

            if ((change & (change - 1)) == 0) // power of 2, only one change, perform below to avoid looping over all tags
            {
                var index = (int)Math.Log(change, 2);
                if (index < tagTypes.Count)
                {
                    Type tagType = tagTypes[index];
                    ApplyTagChange(asset, metricIndex, newValue, index, tagType);
                }
            }
            else // multiple changes
            {
                for (int index = 0; index < TagAttribute.GetAllDescriptions().Count; ++index)
                {
                    if ((change & (1 << index)) != 0)
                    {
                        Type tagType = tagTypes[index];
                        ApplyTagChange(asset, metricIndex, newValue, index, tagType);
                    }
                }
            }
        }
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            Asset asset  = property.serializedObject.targetObject as Asset;
            var   metric = GetMetric(asset, property);
            int   mask   = metric.TagTypes.MaskTypeNames();

            List <string> tagNames = TagAttribute.GetAllDescriptions();

            EditorGUI.BeginChangeCheck();

            int newValue = EditorGUI.MaskField(position, new GUIContent("Tag Types", "Tag types that apply to this metric."), mask, tagNames.ToArray());

            if (EditorGUI.EndChangeCheck())
            {
                OnTagChanged(mask, newValue, property);
            }
        }