Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tab.readonly doesn't endow pairs/ipairs for proxy #1792

Open
dndrks opened this issue Jul 18, 2024 · 0 comments
Open

tab.readonly doesn't endow pairs/ipairs for proxy #1792

dndrks opened this issue Jul 18, 2024 · 0 comments

Comments

@dndrks
Copy link
Member

dndrks commented Jul 18, 2024

issue description + repro

going through documentation tasks, i realized that i expect tab.readonly to create a proxy which also inherits other tab functionality, eg. tab.print.

repro script

function init()
  
  mana = {
    white = {"order", "peace", "light"},
    blue = {"intellect", "logic", "manipulation"},
    black = {"power", "death", "corruption"},
    red = {"freedom", "chaos", "fury"},
    green = {"life", "nature", "evolution"}
  }
  
  mana_green_editable = tab.readonly{
    table = mana, -- which table to copy
    except = {'green'}, -- which keys should remain writeable
  }
  
  tab.print(mana_green_editable)
  
end

since tab.print calls pairs, running the above results in a C stack overflow pointing to

__pairs = function (_) return pairs(proxy) end,

workaround

i'm v dumb about metatable stuff, but i'm able to resolve the stack overflow issue by building and adjusting a local tpairs table which reflects expose + except params. see https://www.diffchecker.com/fNViUcZr/ for side-by-side to current code (chose a different name just for differentiation in testing):

pairs workaround
function treadonly(params)
  local t = params.table
  local exceptions = params.except or {}
  local proxy = {}
  local tpairs = {}
  for k,v in pairs(t) do
    if params.expose == nil or tab.contains(params.expose, k) then
      tpairs[k] = v
    end
  end
  local mt = {
    __index = function(_, k)
      if params.expose == nil or tab.contains(params.expose, k) then
        tpairs[k] = t[k]
        return t[k]
      end
      return nil
    end,
    __newindex = function (_,k,v)
      if (tab.contains(exceptions, k)) then
        t[k] = v
        tpairs[k] = v
      else
        error("'"..k.."', a read-only key, cannot be re-assigned.")
      end
    end,
    __pairs = function (_) return pairs(tpairs) end,
    __ipairs = function (_) return ipairs(tpairs) end,
  }
  setmetatable(proxy, mt)
  return proxy
end

if this is at all reasonable, i'd be happy to PR this fix -- or i'd be happy to PR a much better one with some quick guidance <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant