# frozen_string_literal: true

module FFI
  module Libfuse
    # This namespace contains helper Modules that alter the signature or behaviour of the native {FuseOperations}
    # callbacks
    #
    # There are two types of Adapters
    #
    # 1) Wrap many fuse methods in a proc that manipulates the arguments in a consistent way
    #
    #    These will implement {FuseOperations#fuse_wrappers} to add the proc which can then...
    #
    #    * prepend additional arguments - eg. ({Context})
    #    * wrap common arguments - eg. ({Pathname})
    #    * handle return values/exceptions - eg. ({Safe})
    #    * or just wrap the underlying block - eg. ({Debug})
    #
    # 2) Override specific callback methods to change their signatures
    #
    #    These will prepend an internal module that implements the callback methods,  manipulating the
    #    argument list and passing on to super and then manipulating the result.
    #
    #    The prepend module must include Adapter so that the module methods themselves do not register as
    #    callbacks unless there is an implementation by the including class.
    #
    #    eg. {Ruby}, {Fuse2Compat}, {Fuse3Support}
    module Adapter
      # Does something other than an adapter (ie the underlying filesystem itself) implement fuse_method.
      #
      # Can be called by custom implementations of fuse_respond_to? to confirm that the implementing module
      # is not a type 2 Adapter (which itself will call super)
      def fuse_super_respond_to?(fuse_method)
        return false unless respond_to?(fuse_method)

        m = method(fuse_method)
        m = m.super_method while m && Adapter.include?(m.owner)

        m && true
      end

      # @!visibility private

      # Use {#fuse_super_respond_to?} if no super implementation
      def fuse_respond_to?(fuse_method)
        return super if defined?(super)

        fuse_super_respond_to?(fuse_method)
      end

      class << self
        # @!visibility private

        # is mod an Adapter
        def include?(mod)
          adapters.include?(mod)
        end

        def included(mod)
          adapters << mod
        end

        def adapters
          # Avoid Kernel#open being considered a fuse callback
          @adapters ||= [Kernel, Object, BasicObject]
        end
      end
    end
  end
end

require_relative 'adapter/context'
require_relative 'adapter/thread_local_context'
require_relative 'adapter/debug'
require_relative 'adapter/ruby'
require_relative 'adapter/interrupt'
require_relative 'adapter/pathname'
require_relative 'adapter/fuse3_support'
require_relative 'adapter/fuse2_compat'
