Repository: airbnb/lottie-ios
File: Sources/Private/CoreAnimation/ValueProviderStore.swift (Swift)

Code before:
    self.logger = logger
  }

  // MARK: Internal

  /// Registers an `AnyValueProvider` for the given `AnimationKeypath`
  func setValueProvider(_ valueProvider: AnyValueProvider, keypath: AnimationKeypath) {
    logger.assert(
      valueProvider.typeErasedStorage.isSupportedByCoreAnimationRenderingEngine,
      """
      The Core Animation rendering engine doesn't support Value Providers that vend a closure,
      because that would require calling the closure on the main thread once per frame.
      """)

    let supportedProperties = PropertyName.allCases.map { $0.rawValue }
    let propertyBeingCustomized = keypath.keys.last ?? ""

    logger.assert(
      supportedProperties.contains(propertyBeingCustomized),
      """
      The Core Animation rendering engine currently doesn't support customizing "\(propertyBeingCustomized)" \
      properties. Supported properties are: \(supportedProperties.joined(separator: ", ")).
      """)

    orderedKeyPaths.remove(keypath)
    orderedKeyPaths.insert(keypath, at: orderedKeyPaths.count)
    valueProviders[keypath] = valueProvider
  }

  // Retrieves the custom value keyframes for the given property,
  // if an `AnyValueProvider` was registered for the given keypath.
  func customKeyframes<Value>(
    of customizableProperty: CustomizableProperty<Value>,
    for keypath: AnimationKeypath,
    context: LayerAnimationContext)
    throws -> KeyframeGroup<Value>?
  {
    context.recordHierarchyKeypath?(keypath.fullPath)

    guard let anyValueProvider = valueProvider(for: keypath) else {
      return nil
    }

    // Retrieve the type-erased keyframes from the custom `ValueProvider`
    let typeErasedKeyframes: [Keyframe<Any>]
    switch anyValueProvider.typeErasedStorage {
    case .singleValue(let typeErasedValue):
      typeErasedKeyframes = [Keyframe(typeErasedValue)]

    case .keyframes(let keyframes, _):
      typeErasedKeyframes = keyframes

Review comment (suggestion):
This is just an "append" right? Can we use a built-in method like https://developer.apple.com/documentation/foundation/nsmutableorderedset/1408009-add?

```suggestion
    orderedKeyPaths.add(keypath)
```

Code after:
    self.logger = logger
  }

  // MARK: Internal

  /// Registers an `AnyValueProvider` for the given `AnimationKeypath`
  func setValueProvider(_ valueProvider: AnyValueProvider, keypath: AnimationKeypath) {
    logger.assert(
      valueProvider.typeErasedStorage.isSupportedByCoreAnimationRenderingEngine,
      """
      The Core Animation rendering engine doesn't support Value Providers that vend a closure,
      because that would require calling the closure on the main thread once per frame.
      """)

    let supportedProperties = PropertyName.allCases.map { $0.rawValue }
    let propertyBeingCustomized = keypath.keys.last ?? ""

    logger.assert(
      supportedProperties.contains(propertyBeingCustomized),
      """
      The Core Animation rendering engine currently doesn't support customizing "\(propertyBeingCustomized)" \
      properties. Supported properties are: \(supportedProperties.joined(separator: ", ")).
      """)

    valueProviders.removeAll(where: { $0.keypath == keypath })
    valueProviders.append((keypath: keypath, valueProvider: valueProvider))
  }

  // Retrieves the custom value keyframes for the given property,
  // if an `AnyValueProvider` was registered for the given keypath.
  func customKeyframes<Value>(
    of customizableProperty: CustomizableProperty<Value>,
    for keypath: AnimationKeypath,
    context: LayerAnimationContext)
    throws -> KeyframeGroup<Value>?
  {
    context.recordHierarchyKeypath?(keypath.fullPath)

    guard let anyValueProvider = valueProvider(for: keypath) else {
      return nil
    }

    // Retrieve the type-erased keyframes from the custom `ValueProvider`
    let typeErasedKeyframes: [Keyframe<Any>]
    switch anyValueProvider.typeErasedStorage {
    case .singleValue(let typeErasedValue):
      typeErasedKeyframes = [Keyframe(typeErasedValue)]

    case .keyframes(let keyframes, _):
      typeErasedKeyframes = keyframes