module Bootsnap::LoadPathCache::PathScanner

def native_call(root_path)

def native_call(root_path)
  # NOTE: if https://bugs.ruby-lang.org/issues/21800 is accepted we should be able
  # to have similar performance with pure Ruby
  root_path, contains_bundle_path, ignored_abs_paths, ignored_dir_names = prepare_scan(root_path)
  all_requirables, queue = Native.scan_dir(root_path)
  all_requirables.each(&:freeze)
  queue.reject! do |dir|
    if ignored_dir_names&.include?(dir)
      true
    elsif ignored_abs_paths || contains_bundle_path
      absolute_dir = File.join(root_path, dir)
      ignored_abs_paths&.include?(absolute_dir) ||
        (contains_bundle_path && absolute_dir.start_with?(BUNDLE_PATH))
    end
  end
  while (relative_path = queue.pop)
    absolute_base = File.join(root_path, relative_path)
    requirables, dirs = Native.scan_dir(absolute_base)
    dirs.reject! do |dir|
      if ignored_dir_names&.include?(dir)
        true
      elsif ignored_abs_paths || contains_bundle_path
        absolute_dir = File.join(absolute_base, dir)
        ignored_abs_paths&.include?(absolute_dir) ||
          (contains_bundle_path && absolute_dir.start_with?(BUNDLE_PATH))
      end
    end
    dirs.map! { |f| File.join(relative_path, f).freeze }
    requirables.map! { |f| File.join(relative_path, f).freeze }
    all_requirables.concat(requirables)
    queue.concat(dirs)
  end
  all_requirables
end

def prepare_scan(root_path)

def prepare_scan(root_path)
  root_path = File.expand_path(root_path.to_s).freeze
  # If the bundle path is a descendent of this path, we do additional
  # checks to prevent recursing into the bundle path as we recurse
  # through this path. We don't want to scan the bundle path because
  # anything useful in it will be present on other load path items.
  #
  # This can happen if, for example, the user adds '.' to the load path,
  # and the bundle path is '.bundle'.
  contains_bundle_path = BUNDLE_PATH.start_with?(root_path)
  ignored_abs_paths, ignored_dir_names = ignored_directories.partition { |p| File.absolute_path?(p) }
  ignored_abs_paths = nil if ignored_abs_paths.empty?
  ignored_dir_names = nil if ignored_dir_names.empty?
  [root_path, contains_bundle_path, ignored_abs_paths, ignored_dir_names]
end

def ruby_call(root_path)

def ruby_call(root_path)
  root_path, contains_bundle_path, ignored_abs_paths, ignored_dir_names = prepare_scan(root_path)
  return [] unless File.directory?(root_path)
  requirables = []
  walk(root_path, nil, ignored_abs_paths, ignored_dir_names) do |relative_path, absolute_path, is_directory|
    if is_directory
      !contains_bundle_path || !absolute_path.start_with?(BUNDLE_PATH)
    elsif relative_path.end_with?(*REQUIRABLE_EXTENSIONS)
      requirables << relative_path.freeze
    end
  end
  requirables
end

def walk(absolute_dir_path, relative_dir_path, ignored_abs_paths, ignored_dir_names, &block)

def walk(absolute_dir_path, relative_dir_path, ignored_abs_paths, ignored_dir_names, &block)
  Dir.foreach(absolute_dir_path) do |name|
    next if name.start_with?(".")
    relative_path = relative_dir_path ? File.join(relative_dir_path, name) : name
    absolute_path = File.join(absolute_dir_path, name)
    if File.directory?(absolute_path)
      next if ignored_dir_names&.include?(name) || ignored_abs_paths&.include?(absolute_path)
      if yield relative_path, absolute_path, true
        walk(absolute_path, relative_path, ignored_abs_paths, ignored_dir_names, &block)
      end
    else
      yield relative_path, absolute_path, false
    end
  end
end