Sha256: ca76d950a837f2e447f38eab170cf4d809fdc77ec415e46b2f871e9f24c6d712

Contents?: true

Size: 1.92 KB

Versions: 1

Compression:

Stored size: 1.92 KB

Contents

# frozen_string_literal: true

require 'concurrent'
require 'plumb/steppable'
require 'plumb/result'
require 'plumb/hash_class'

module Plumb
  class ArrayClass
    include Steppable

    attr_reader :element_type

    def initialize(element_type: Types::Any)
      @element_type = case element_type
      when Steppable
        element_type
      when ::Hash
        HashClass.new(element_type)
      else
        raise ArgumentError,
          "element_type #{element_type.inspect} must be a Steppable"
      end

      freeze
    end

    def of(element_type)
      self.class.new(element_type:)
    end

    alias [] of

    def concurrent
      ConcurrentArrayClass.new(element_type:)
    end

    private def _inspect
      %(#{name}[#{element_type}])
    end

    def call(result)
      return result.invalid(errors: 'is not an Array') unless result.value.is_a?(::Enumerable)

      values, errors = map_array_elements(result.value)
      return result.valid(values) unless errors.any?

      result.invalid(errors:)
    end

    private

    def map_array_elements(list)
      # Reuse the same result object for each element
      # to decrease object allocation.
      # Steps might return the same result instance, so we map the values directly
      # separate from the errors.
      element_result = BLANK_RESULT.dup
      errors = {}
      values = list.map.with_index do |e, idx|
        re = element_type.call(element_result.reset(e))
        errors[idx] = re.errors unless re.valid?
        re.value
      end

      [values, errors]
    end

    class ConcurrentArrayClass < self
      private

      def map_array_elements(list)
        errors = {}

        values = list
          .map { |e| Concurrent::Future.execute { element_type.resolve(e) } }
          .map.with_index do |f, idx|
            re = f.value
            errors[idx] = f.reason if f.rejected?
            re.value
          end

        [values, errors]
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
plumb-0.0.1 lib/plumb/array_class.rb