diff options
Diffstat (limited to 'lua/clever_f')
| -rw-r--r-- | lua/clever_f/acquisition_service.lua | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/lua/clever_f/acquisition_service.lua b/lua/clever_f/acquisition_service.lua new file mode 100644 index 0000000..cdbcd81 --- /dev/null +++ b/lua/clever_f/acquisition_service.lua @@ -0,0 +1,137 @@ +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 |
