local domain = require("clever_f.domain") local M = {} local AcquisitionRequest = {} local AcquisitionService = {} AcquisitionService.__index = AcquisitionService M.AcquisitionRequest = AcquisitionRequest M.AcquisitionService = AcquisitionService local request_records = setmetatable({}, { __mode = "k" }) local service_records = setmetatable({}, { __mode = "k" }) local function fail(message, level) error(message, (level or 1) + 1) end local function normalize_macro_state(value) if type(value) == "table" and not domain.MacroState.is(value) then value = value.register end return domain.MacroState.new(value) end local request_metatable = { __index = function(request, key) local method = AcquisitionRequest[key] if method ~= nil then return method end return request_records[request][key] end, __newindex = function() fail("AcquisitionRequest values are immutable", 2) end, __tostring = function(request) return "acquisition-request:" .. request_records[request].descriptor.value end, __metatable = "clever_f.acquisition_service.AcquisitionRequest", } function AcquisitionRequest.new(descriptor, context, position, count, macro_state) if AcquisitionRequest.is(descriptor) then return descriptor end if type(descriptor) == "table" and not domain.Descriptor.is(descriptor) then local options = descriptor descriptor = options.descriptor context = options.context position = options.position or options.origin count = options.count macro_state = options.macro_state end local request = setmetatable({}, request_metatable) request_records[request] = { descriptor = domain.Descriptor.from_string(descriptor), context = domain.ModeContext.from_full_mode(context), position = domain.Position.coerce(position), count = domain.Count.new(count), macro_state = normalize_macro_state(macro_state), } return request end function AcquisitionRequest.is(value) return type(value) == "table" and request_records[value] ~= nil end function AcquisitionRequest:to_table() return { descriptor = self.descriptor.value, context = self.context.key, position = self.position:to_table(), count = self.count.value, macro_register = self.macro_state.register, } end local function normalize_options(options, dependencies) if AcquisitionService.is(options) and dependencies == nil then return options end if type(options) ~= "table" then fail("AcquisitionService options must be a table", 3) end if options.host ~= nil then if dependencies ~= nil then fail("AcquisitionService dependencies must be part of its options", 3) end return options end local result = {} for key, value in pairs(dependencies or {}) do result[key] = value end result.host = options return result end function AcquisitionService.new(options, dependencies) options = normalize_options(options, dependencies) if AcquisitionService.is(options) then return options end if type(options.host) ~= "table" then fail("AcquisitionService host must be a table", 2) end local service = setmetatable({}, AcquisitionService) service_records[service] = { host = options.host, } return service end function AcquisitionService.is(value) return type(value) == "table" and service_records[value] ~= nil end function AcquisitionService:request(descriptor, context, position, count, macro_state) return AcquisitionRequest.new(descriptor, context, position, count, macro_state) end function AcquisitionService:acquire(descriptor, context, position, count, macro_state) return self:request(descriptor, context, position, count, macro_state) end function M.new(options, dependencies) return AcquisitionService.new(options, dependencies) end setmetatable(M, { __call = function(_, options, dependencies) return AcquisitionService.new(options, dependencies) end, }) return M