# # encoding: utf-8 # frozen_string_literal: true # # frozen_string_literal: true # # require "forwardable" # # module Carbon # module Concrete # # A "request." This is used to note the generics that a given module # # should be compiled with. This is used for items to note the dependencies # # that an item has; otherwise, it is used in the index for build # # information. # # # # @note # # **This class is frozen upon initialization.** This means that any # # attempt to modify it will result in an error. In most cases, the # # attributes on this class will also be frozen, as well. # class Request # extend Forwardable # # # The interned name of a module. This is used for module lookup. This # # contains no generic information. For generic functions, all generics # # are pushed onto the defining module. # # # # @api public # # @example # # request.intern # => "Carbon::Pointer" # # @note See {Item::Base#intern} For more information about interned # # names. # # @return [::String] # attr_reader :intern # # # The generics of the request. Even if the request has no definable # # generics, these are still kept in place for both name information and # # for placement information (e.g. identity and size). # # # # @api public # # @example # # request.generics # => [#] # # @return [] # attr_reader :generics # # # Initialize the request with the given interned name and generics, # # and then freezes the request. # # # # @api public # # @see #intern # # @see #generics # # @param intern [::String] The interned name. # # @param generics [] The generics. # def initialize(intern, generics) # @intern = intern # @generics = generics # deep_freeze! # end # # # Replaces this request or this request's generics with the corresponding # # correct module. This is designed to resolve generic names; for # # example, it resolves `Carbon::Pointer` to # # `Carbon::Pointer` with the right argument. It checks # # for three seperate cases. # # # # 1. The request has no generics, and the request's {#intern} has a # # mapping in the argument. In this case, it creates a new request # # object with the new module's name and no generics (because the # # mapping could not have added any worthwhile generics). # # 2. The request has no generics, and the request's {#intern} has no # # mapping in the argument. In this case, it returns itself. # # 3. The request has generics. In this case, the generics are mapped # # using {Type::Generic#sub}, and a new request is created with the # # mapped generics. # # # # @api public # # @example # # string # => # # # request.intern # => "Carbon::Pointer" # # request.generics # => [#] # # mapped = request.sub("T" => string) # # mapped.intern # => "Carbon::Pointer" # # request.generics.first.equal?(string) # => true # # @param mapping [{::String => Type::Generic}] The mapping. # # @return [Request] The new request, if the request has no generics, # # and the request's {#intern} is not a key in the mapping, or if # # the request has generics. # # @return [self] If the request has no generics and it is not a key # # in the mapping. # def sub(mapping) # case [@generics.none?, mapping.key?(@intern)] # when [true, true] # Request.new(mapping[@intern].name.intern, []) # when [true, false] # self # else # generics = @generics.map { |generic| generic.sub(mapping) } # Request.new(intern, generics) # end # end # # # Compares this request to another. If this request _is_ the other # # request, it returns true; otherwise, if the other is a request, and # # the other request's {#intern} is equal to this request's, it # # returns true; otherwise, it returns false. # # # # @api public # # @param other [Request, ::String, ::Object] The object to compare. # # @return [::Boolean] # def ==(other) # equal?(other) || # (other.is_a?(Request) && other.intern == intern && # other.generics == generics) # end # # alias_method :eql?, :== # # # Creates a hash of the request. This is used mostly in the Hash # # class. # # # # @api private # # @return [Numeric] # def hash # @intern.hash # end # # # Returns a string representation of this request. This includes all # # generics that are associated with the request, if applicable. # # # # @api public # # @return [::String] # def to_s # if @generics.any? # "#{@intern}<#{@generics.map(&:to_s).join(', ')}>".freeze # else # @intern # end # end # end # end # end