]> source.dussan.org Git - rspamd.git/commitdiff
[Minor] Add tableshape library from https://github.com/leafo/tableshape
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 19 Sep 2018 10:51:58 +0000 (11:51 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 19 Sep 2018 13:33:53 +0000 (14:33 +0100)
CMakeLists.txt
contrib/DEPENDENCY_INFO.md
contrib/lua-tableshape/LICENSE [new file with mode: 0644]
contrib/lua-tableshape/tableshape.lua [new file with mode: 0644]

index e75e85d7bd26c0c64ec07160d7833433921b1a12..b9313d30cb9f8973bde3587ec4564b9faee777dd 100644 (file)
@@ -1376,6 +1376,7 @@ ENDFOREACH(LUA_LIB)
 # Install lua fun library
 INSTALL(FILES "contrib/lua-fun/fun.lua" DESTINATION ${LUALIBDIR})
 INSTALL(FILES "contrib/lua-argparse/argparse.lua" DESTINATION ${LUALIBDIR})
+INSTALL(FILES "contrib/lua-tableshape/tableshape.lua" DESTINATION ${LUALIBDIR})
 
 IF(ENABLE_TORCH MATCHES "ON")
        INSTALL(FILES "contrib/lua-moses/moses.lua" DESTINATION ${LUALIBDIR})
index 3b54013600573ec83f57f9dc9f6edfd8ae4931ff..f3996eed60f5cdfc27e17a73069fd9c4f73be709 100644 (file)
@@ -1,16 +1,17 @@
 # Rspamd Dependency Info
 
-- aho-corasick      Version: ?      License: LGPL-3.0               Patched: ?
-- cdb               Version: 1.1.0  License: Public Domain / CC0    Patched: ?
-- hiredis           Version: 0.13.3 License: BSD-3-Clause           Patched: ?
-- lc-btrie          Version: ?      License: BSD-3-Clause           Patched: ?
-- lgpl              Version: ?      License: LGPL-2.1               Patched: ?
-- libottery         Version: ?      License: Public Domain / CC0    Patched: ?
+- aho-corasick      Version: ?      License: LGPL-3.0               Patched: YES
+- cdb               Version: 1.1.0  License: Public Domain / CC0    Patched: NO
+- hiredis           Version: 0.13.3 License: BSD-3-Clause           Patched: YES
+- lc-btrie          Version: ?      License: BSD-3-Clause           Patched: YES
+- lgpl              Version: ?      License: LGPL-2.1               Patched: NO
+- libottery         Version: ?      License: Public Domain / CC0    Patched: YES
 - librdns           Version: ?      License: BSD-2-Clause           Patched: ?
 - libucl            Version: ?      License: BSD-2-Clause           Patched: ?
 - linenoise         Version: 1.0    License: BSD-2-Clause           Patched: ?
-- lpeg:             Version: 1.0    License: MIT                    Patched: ?
-- lua-fun           Version: ?      License: MIT                    Patched: ?
+- lpeg:             Version: 1.0    License: MIT                    Patched: NO
+- lua-fun           Version: ?      License: MIT                    Patched: NO
+- lua-tableshape    Version: ae67256 License: MIT                   Patched: NO
 - moses             Version: ?      License: MIT                    Patched: ?
 - mumhash           Version: ?      License: MIT                    Patched: ?
 - ngx-http-parser   Version: 2.2.0  License: MIT                    Patched: ?
@@ -18,7 +19,7 @@
                     Version: ?      License: MIT                    Patched: ?
 - snowball          Version: ?      License: BSD-3-Clause           Patched: ?
 - t1ha              Version: ?      License: Zlib                   Patched: ?
-- torch             Version: ?      License: ASL-2.0 v BSD-3-Clause Patched: ?
+- torch             Version: ?      License: ASL-2.0 v BSD-3-Clause Patched: YES
 - uthash            Version: 1.9.8  License: BSD                    Patched: ?
 - xxhash            Version: ?      License: BSD                    Patched: ?
-- zstd              Version: 1.3.1  License: BSD                    Patched: ?
+- zstd              Version: 1.3.1  License: BSD                    Patched: NO
diff --git a/contrib/lua-tableshape/LICENSE b/contrib/lua-tableshape/LICENSE
new file mode 100644 (file)
index 0000000..38ba5fc
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (C) 2018 by Leaf Corcoran
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/contrib/lua-tableshape/tableshape.lua b/contrib/lua-tableshape/tableshape.lua
new file mode 100644 (file)
index 0000000..0f1f710
--- /dev/null
@@ -0,0 +1,1870 @@
+local OptionalType, TaggedType, types
+local FailedTransform = { }
+local unpack = unpack or table.unpack
+local clone_state
+clone_state = function(state_obj)
+  if type(state_obj) ~= "table" then
+    return { }
+  end
+  local out
+  do
+    local _tbl_0 = { }
+    for k, v in pairs(state_obj) do
+      _tbl_0[k] = v
+    end
+    out = _tbl_0
+  end
+  do
+    local mt = getmetatable(state_obj)
+    if mt then
+      setmetatable(out, mt)
+    end
+  end
+  return out
+end
+local BaseType, TransformNode, SequenceNode, FirstOfNode, DescribeNode
+local describe_literal
+describe_literal = function(val)
+  local _exp_0 = type(val)
+  if "string" == _exp_0 then
+    if not val:match('"') then
+      return "\"" .. tostring(val) .. "\""
+    elseif not val:match("'") then
+      return "'" .. tostring(val) .. "'"
+    else
+      return "`" .. tostring(val) .. "`"
+    end
+  else
+    if BaseType:is_base_type(val) then
+      return val:_describe()
+    else
+      return tostring(val)
+    end
+  end
+end
+local join_names
+join_names = function(items, sep, last_sep)
+  if sep == nil then
+    sep = ", "
+  end
+  local count = #items
+  local chunks = { }
+  for idx, name in ipairs(items) do
+    if idx > 1 then
+      local current_sep
+      if idx == count then
+        current_sep = last_sep or sep
+      else
+        current_sep = sep
+      end
+      table.insert(chunks, current_sep)
+    end
+    table.insert(chunks, name)
+  end
+  return table.concat(chunks)
+end
+do
+  local _class_0
+  local _base_0 = {
+    __eq = function(self, other)
+      if BaseType:is_base_type(other) then
+        return other(self)
+      else
+        return self(other[1])
+      end
+    end,
+    __div = function(self, fn)
+      return TransformNode(self, fn)
+    end,
+    __mod = function(self, fn)
+      do
+        local _with_0 = TransformNode(self, fn)
+        _with_0.with_state = true
+        return _with_0
+      end
+    end,
+    __mul = function(self, right)
+      return SequenceNode(self, right)
+    end,
+    __add = function(self, right)
+      if self.__class == FirstOfNode then
+        local options = {
+          unpack(self.options)
+        }
+        table.insert(options, right)
+        return FirstOfNode(unpack(options))
+      else
+        return FirstOfNode(self, right)
+      end
+    end,
+    _describe = function(self)
+      return error("Node missing _describe: " .. tostring(self.__class.__name))
+    end,
+    check_value = function(self, ...)
+      local value, state_or_err = self:_transform(...)
+      if value == FailedTransform then
+        return nil, state_or_err
+      end
+      if type(state_or_err) == "table" then
+        return state_or_err
+      else
+        return true
+      end
+    end,
+    transform = function(self, ...)
+      local value, state_or_err = self:_transform(...)
+      if value == FailedTransform then
+        return nil, state_or_err
+      end
+      if type(state_or_err) == "table" then
+        return value, state_or_err
+      else
+        return value
+      end
+    end,
+    repair = function(self, ...)
+      return self:transform(...)
+    end,
+    on_repair = function(self, fn)
+      return (self + types.any / fn * self):describe(function()
+        return self:_describe()
+      end)
+    end,
+    is_optional = function(self)
+      return OptionalType(self)
+    end,
+    describe = function(self, ...)
+      return DescribeNode(self, ...)
+    end,
+    tag = function(self, name)
+      return TaggedType(self, {
+        tag = name
+      })
+    end,
+    clone_opts = function(self, merge)
+      local opts
+      if self.opts then
+        do
+          local _tbl_0 = { }
+          for k, v in pairs(self.opts) do
+            _tbl_0[k] = v
+          end
+          opts = _tbl_0
+        end
+      else
+        opts = { }
+      end
+      if merge then
+        for k, v in pairs(merge) do
+          opts[k] = v
+        end
+      end
+      return opts
+    end,
+    __call = function(self, ...)
+      return self:check_value(...)
+    end
+  }
+  _base_0.__index = _base_0
+  _class_0 = setmetatable({
+    __init = function(self)
+      if self.opts then
+        self._describe = self.opts.describe
+      end
+    end,
+    __base = _base_0,
+    __name = "BaseType"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.is_base_type = function(self, val)
+    if not (type(val) == "table") then
+      return false
+    end
+    local cls = val and val.__class
+    if not (cls) then
+      return false
+    end
+    if BaseType == cls then
+      return true
+    end
+    return self:is_base_type(cls.__parent)
+  end
+  self.__inherited = function(self, cls)
+    cls.__base.__call = cls.__call
+    cls.__base.__eq = self.__eq
+    cls.__base.__div = self.__div
+    cls.__base.__mod = self.__mod
+    cls.__base.__mul = self.__mul
+    cls.__base.__add = self.__add
+    local mt = getmetatable(cls)
+    local create = mt.__call
+    mt.__call = function(cls, ...)
+      local ret = create(cls, ...)
+      if ret.opts and ret.opts.optional then
+        return ret:is_optional()
+      else
+        return ret
+      end
+    end
+  end
+  BaseType = _class_0
+end
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _describe = function(self)
+      return self.node:_describe()
+    end,
+    _transform = function(self, value, state)
+      local state_or_err
+      value, state_or_err = self.node:_transform(value, state)
+      if value == FailedTransform then
+        return FailedTransform, state_or_err
+      else
+        local out
+        local _exp_0 = type(self.t_fn)
+        if "function" == _exp_0 then
+          if self.with_state then
+            out = self.t_fn(value, state_or_err)
+          else
+            out = self.t_fn(value)
+          end
+        else
+          out = self.t_fn
+        end
+        return out, state_or_err
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, node, t_fn)
+      self.node, self.t_fn = node, t_fn
+      return assert(self.node, "missing node for transform")
+    end,
+    __base = _base_0,
+    __name = "TransformNode",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.transformer = true
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  TransformNode = _class_0
+end
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _describe = function(self)
+      local item_names
+      do
+        local _accum_0 = { }
+        local _len_0 = 1
+        local _list_0 = self.sequence
+        for _index_0 = 1, #_list_0 do
+          local i = _list_0[_index_0]
+          if type(i) == "table" and i._describe then
+            _accum_0[_len_0] = i:_describe()
+          else
+            _accum_0[_len_0] = describe_literal(i)
+          end
+          _len_0 = _len_0 + 1
+        end
+        item_names = _accum_0
+      end
+      return join_names(item_names, " then ")
+    end,
+    _transform = function(self, value, state)
+      local _list_0 = self.sequence
+      for _index_0 = 1, #_list_0 do
+        local node = _list_0[_index_0]
+        value, state = node:_transform(value, state)
+        if value == FailedTransform then
+          break
+        end
+      end
+      return value, state
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, ...)
+      self.sequence = {
+        ...
+      }
+    end,
+    __base = _base_0,
+    __name = "SequenceNode",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.transformer = true
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  SequenceNode = _class_0
+end
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _describe = function(self)
+      local item_names
+      do
+        local _accum_0 = { }
+        local _len_0 = 1
+        local _list_0 = self.options
+        for _index_0 = 1, #_list_0 do
+          local i = _list_0[_index_0]
+          if type(i) == "table" and i._describe then
+            _accum_0[_len_0] = i:_describe()
+          else
+            _accum_0[_len_0] = describe_literal(i)
+          end
+          _len_0 = _len_0 + 1
+        end
+        item_names = _accum_0
+      end
+      return join_names(item_names, ", ", ", or ")
+    end,
+    _transform = function(self, value, state)
+      if not (self.options[1]) then
+        return FailedTransform, "no options for node"
+      end
+      local _list_0 = self.options
+      for _index_0 = 1, #_list_0 do
+        local node = _list_0[_index_0]
+        local new_val, new_state = node:_transform(value, state)
+        if not (new_val == FailedTransform) then
+          return new_val, new_state
+        end
+      end
+      return FailedTransform, "expected " .. tostring(self:_describe())
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, ...)
+      self.options = {
+        ...
+      }
+    end,
+    __base = _base_0,
+    __name = "FirstOfNode",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.transformer = true
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  FirstOfNode = _class_0
+end
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _transform = function(self, input, ...)
+      local value, state = self.node:_transform(input, ...)
+      if value == FailedTransform then
+        local err
+        if self.err_handler then
+          err = self.err_handler(input, state)
+        else
+          err = "expected " .. tostring(self:_describe())
+        end
+        return FailedTransform, err
+      end
+      return value, state
+    end,
+    describe = function(self, ...)
+      return DescribeNode(self.node, ...)
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, node, describe)
+      self.node = node
+      local err_message
+      if type(describe) == "table" then
+        describe, err_message = describe.type, describe.error
+      end
+      if type(describe) == "string" then
+        self._describe = function()
+          return describe
+        end
+      else
+        self._describe = describe
+      end
+      if err_message then
+        if type(err_message) == "string" then
+          self.err_handler = function()
+            return err_message
+          end
+        else
+          self.err_handler = err_message
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "DescribeNode",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  DescribeNode = _class_0
+end
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    update_state = function(self, state, value, ...)
+      local out = clone_state(state)
+      if self.tag_type == "function" then
+        if select("#", ...) > 0 then
+          self.tag_name(out, ..., value)
+        else
+          self.tag_name(out, value)
+        end
+      else
+        if self.tag_array then
+          local existing = out[self.tag_name]
+          if type(existing) == "table" then
+            local copy
+            do
+              local _tbl_0 = { }
+              for k, v in pairs(existing) do
+                _tbl_0[k] = v
+              end
+              copy = _tbl_0
+            end
+            table.insert(copy, value)
+            out[self.tag_name] = copy
+          else
+            out[self.tag_name] = {
+              value
+            }
+          end
+        else
+          out[self.tag_name] = value
+        end
+      end
+      return out
+    end,
+    _transform = function(self, value, state)
+      value, state = self.base_type:_transform(value, state)
+      if value == FailedTransform then
+        return FailedTransform, state
+      end
+      state = self:update_state(state, value)
+      return value, state
+    end,
+    _describe = function(self)
+      local base_description = self.base_type:_describe()
+      return tostring(base_description) .. " tagged " .. tostring(describe_literal(self.tag))
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, base_type, opts)
+      self.base_type = base_type
+      self.tag_name = assert(opts.tag, "tagged type missing tag")
+      self.tag_type = type(self.tag_name)
+      if self.tag_type == "string" then
+        if self.tag_name:match("%[%]$") then
+          self.tag_name = self.tag_name:sub(1, -3)
+          self.tag_array = true
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "TaggedType",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  TaggedType = _class_0
+end
+local TagScopeType
+do
+  local _class_0
+  local _parent_0 = TaggedType
+  local _base_0 = {
+    create_scope_state = function(self, state)
+      return nil
+    end,
+    _transform = function(self, value, state)
+      local scope
+      value, scope = self.base_type:_transform(value, self:create_scope_state(state))
+      if value == FailedTransform then
+        return FailedTransform, scope
+      end
+      if self.tag_name then
+        state = self:update_state(state, scope, value)
+      end
+      return value, state
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, base_type, opts)
+      if opts then
+        return _class_0.__parent.__init(self, base_type, opts)
+      else
+        self.base_type = base_type
+      end
+    end,
+    __base = _base_0,
+    __name = "TagScopeType",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  TagScopeType = _class_0
+end
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _transform = function(self, value, state)
+      if value == nil then
+        return value, state
+      end
+      return self.base_type:_transform(value, state)
+    end,
+    is_optional = function(self)
+      return self
+    end,
+    _describe = function(self)
+      if self.base_type._describe then
+        local base_description = self.base_type:_describe()
+        return "optional " .. tostring(base_description)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, base_type, opts)
+      self.base_type, self.opts = base_type, opts
+      _class_0.__parent.__init(self)
+      return assert(BaseType:is_base_type(base_type), "expected a type checker")
+    end,
+    __base = _base_0,
+    __name = "OptionalType",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  OptionalType = _class_0
+end
+local AnyType
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _transform = function(self, v, state)
+      return v, state
+    end,
+    _describe = function(self)
+      return "anything"
+    end,
+    is_optional = function(self)
+      return self
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, ...)
+      return _class_0.__parent.__init(self, ...)
+    end,
+    __base = _base_0,
+    __name = "AnyType",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  AnyType = _class_0
+end
+local Type
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _transform = function(self, value, state)
+      local got = type(value)
+      if self.t ~= got then
+        return FailedTransform, "expected type " .. tostring(describe_literal(self.t)) .. ", got " .. tostring(describe_literal(got))
+      end
+      if self.length_type then
+        local len = #value
+        local res
+        res, state = self.length_type:_transform(len, state)
+        if res == FailedTransform then
+          return FailedTransform, tostring(self.t) .. " length " .. tostring(state) .. ", got " .. tostring(len)
+        end
+      end
+      return value, state
+    end,
+    length = function(self, left, right)
+      local l
+      if BaseType:is_base_type(left) then
+        l = left
+      else
+        l = types.range(left, right)
+      end
+      return Type(self.t, self:clone_opts({
+        length = l
+      }))
+    end,
+    _describe = function(self)
+      local t = "type " .. tostring(describe_literal(self.t))
+      if self.length_type then
+        t = t .. " length_type " .. tostring(self.length_type:_describe())
+      end
+      return t
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, t, opts)
+      self.t, self.opts = t, opts
+      if self.opts then
+        self.length_type = self.opts.length
+      end
+      return _class_0.__parent.__init(self)
+    end,
+    __base = _base_0,
+    __name = "Type",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Type = _class_0
+end
+local ArrayType
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _describe = function(self)
+      return "an array"
+    end,
+    _transform = function(self, value, state)
+      if not (type(value) == "table") then
+        return FailedTransform, "expecting table"
+      end
+      local k = 1
+      for i, v in pairs(value) do
+        if not (type(i) == "number") then
+          return FailedTransform, "non number field: " .. tostring(i)
+        end
+        if not (i == k) then
+          return FailedTransform, "non array index, got " .. tostring(describe_literal(i)) .. " but expected " .. tostring(describe_literal(k))
+        end
+        k = k + 1
+      end
+      return value, state
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, opts)
+      self.opts = opts
+      return _class_0.__parent.__init(self)
+    end,
+    __base = _base_0,
+    __name = "ArrayType",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  ArrayType = _class_0
+end
+local OneOf
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _describe = function(self)
+      local item_names
+      do
+        local _accum_0 = { }
+        local _len_0 = 1
+        local _list_0 = self.options
+        for _index_0 = 1, #_list_0 do
+          local i = _list_0[_index_0]
+          if type(i) == "table" and i._describe then
+            _accum_0[_len_0] = i:_describe()
+          else
+            _accum_0[_len_0] = describe_literal(i)
+          end
+          _len_0 = _len_0 + 1
+        end
+        item_names = _accum_0
+      end
+      return tostring(join_names(item_names, ", ", ", or "))
+    end,
+    _transform = function(self, value, state)
+      if self.options_hash then
+        if self.options_hash[value] then
+          return value, state
+        end
+      else
+        local _list_0 = self.options
+        for _index_0 = 1, #_list_0 do
+          local _continue_0 = false
+          repeat
+            local item = _list_0[_index_0]
+            if item == value then
+              return value, state
+            end
+            if BaseType:is_base_type(item) then
+              local new_value, new_state = item:_transform(value, state)
+              if new_value == FailedTransform then
+                _continue_0 = true
+                break
+              end
+              return new_value, new_state
+            end
+            _continue_0 = true
+          until true
+          if not _continue_0 then
+            break
+          end
+        end
+      end
+      return FailedTransform, "expected " .. tostring(self:_describe())
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, options, opts)
+      self.options, self.opts = options, opts
+      _class_0.__parent.__init(self)
+      assert(type(self.options) == "table", "expected table for options in one_of")
+      local fast_opts = types.array_of(types.number + types.string)
+      if fast_opts(self.options) then
+        do
+          local _tbl_0 = { }
+          local _list_0 = self.options
+          for _index_0 = 1, #_list_0 do
+            local v = _list_0[_index_0]
+            _tbl_0[v] = true
+          end
+          self.options_hash = _tbl_0
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "OneOf",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  OneOf = _class_0
+end
+local AllOf
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _describe = function(self)
+      local item_names
+      do
+        local _accum_0 = { }
+        local _len_0 = 1
+        local _list_0 = self.types
+        for _index_0 = 1, #_list_0 do
+          local i = _list_0[_index_0]
+          if type(i) == "table" and i._describe then
+            _accum_0[_len_0] = i:_describe()
+          else
+            _accum_0[_len_0] = describe_literal(i)
+          end
+          _len_0 = _len_0 + 1
+        end
+        item_names = _accum_0
+      end
+      return join_names(item_names, " and ")
+    end,
+    _transform = function(self, value, state)
+      local _list_0 = self.types
+      for _index_0 = 1, #_list_0 do
+        local t = _list_0[_index_0]
+        value, state = t:_transform(value, state)
+        if value == FailedTransform then
+          return FailedTransform, state
+        end
+      end
+      return value, state
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, types, opts)
+      self.types, self.opts = types, opts
+      _class_0.__parent.__init(self)
+      assert(type(self.types) == "table", "expected table for first argument")
+      local _list_0 = self.types
+      for _index_0 = 1, #_list_0 do
+        local checker = _list_0[_index_0]
+        assert(BaseType:is_base_type(checker), "all_of expects all type checkers")
+      end
+    end,
+    __base = _base_0,
+    __name = "AllOf",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  AllOf = _class_0
+end
+local ArrayOf
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _describe = function(self)
+      return "array of " .. tostring(describe_literal(self.expected))
+    end,
+    _transform = function(self, value, state)
+      local pass, err = types.table(value)
+      if not (pass) then
+        return FailedTransform, err
+      end
+      if self.length_type then
+        local len = #value
+        local res
+        res, state = self.length_type:_transform(len, state)
+        if res == FailedTransform then
+          return FailedTransform, "array length " .. tostring(state) .. ", got " .. tostring(len)
+        end
+      end
+      local is_literal = not BaseType:is_base_type(self.expected)
+      local copy, k
+      for idx, item in ipairs(value) do
+        local skip_item = false
+        local transformed_item
+        if is_literal then
+          if self.expected ~= item then
+            return FailedTransform, "array item " .. tostring(idx) .. ": expected " .. tostring(describe_literal(self.expected))
+          else
+            transformed_item = item
+          end
+        else
+          local item_val
+          item_val, state = self.expected:_transform(item, state)
+          if item_val == FailedTransform then
+            return FailedTransform, "array item " .. tostring(idx) .. ": " .. tostring(state)
+          end
+          if item_val == nil and not self.keep_nils then
+            skip_item = true
+          else
+            transformed_item = item_val
+          end
+        end
+        if transformed_item ~= item or skip_item then
+          if not (copy) then
+            do
+              local _accum_0 = { }
+              local _len_0 = 1
+              local _max_0 = idx - 1
+              for _index_0 = 1, _max_0 < 0 and #value + _max_0 or _max_0 do
+                local i = value[_index_0]
+                _accum_0[_len_0] = i
+                _len_0 = _len_0 + 1
+              end
+              copy = _accum_0
+            end
+            k = idx
+          end
+        end
+        if copy and not skip_item then
+          copy[k] = transformed_item
+          k = k + 1
+        end
+      end
+      return copy or value, state
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, expected, opts)
+      self.expected, self.opts = expected, opts
+      if self.opts then
+        self.keep_nils = self.opts.keep_nils
+        self.length_type = self.opts.length
+      end
+      return _class_0.__parent.__init(self)
+    end,
+    __base = _base_0,
+    __name = "ArrayOf",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.type_err_message = "expecting table"
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  ArrayOf = _class_0
+end
+local MapOf
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _transform = function(self, value, state)
+      local pass, err = types.table(value)
+      if not (pass) then
+        return FailedTransform, err
+      end
+      local key_literal = not BaseType:is_base_type(self.expected_key)
+      local value_literal = not BaseType:is_base_type(self.expected_value)
+      local transformed = false
+      local out = { }
+      for k, v in pairs(value) do
+        local _continue_0 = false
+        repeat
+          local new_k = k
+          local new_v = v
+          if key_literal then
+            if k ~= self.expected_key then
+              return FailedTransform, "map key expected " .. tostring(describe_literal(self.expected_key))
+            end
+          else
+            new_k, state = self.expected_key:_transform(k, state)
+            if new_k == FailedTransform then
+              return FailedTransform, "map key " .. tostring(state)
+            end
+          end
+          if value_literal then
+            if v ~= self.expected_value then
+              return FailedTransform, "map value expected " .. tostring(describe_literal(self.expected_value))
+            end
+          else
+            new_v, state = self.expected_value:_transform(v, state)
+            if new_v == FailedTransform then
+              return FailedTransform, "map value " .. tostring(state)
+            end
+          end
+          if new_k ~= k or new_v ~= v then
+            transformed = true
+          end
+          if new_k == nil then
+            _continue_0 = true
+            break
+          end
+          out[new_k] = new_v
+          _continue_0 = true
+        until true
+        if not _continue_0 then
+          break
+        end
+      end
+      return transformed and out or value, state
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, expected_key, expected_value, opts)
+      self.expected_key, self.expected_value, self.opts = expected_key, expected_value, opts
+      return _class_0.__parent.__init(self)
+    end,
+    __base = _base_0,
+    __name = "MapOf",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  MapOf = _class_0
+end
+local Shape
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    is_open = function(self)
+      return Shape(self.shape, self:clone_opts({
+        open = true
+      }))
+    end,
+    _describe = function(self)
+      local parts
+      do
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.shape) do
+          _accum_0[_len_0] = tostring(describe_literal(k)) .. " = " .. tostring(describe_literal(v))
+          _len_0 = _len_0 + 1
+        end
+        parts = _accum_0
+      end
+      return "{ " .. tostring(table.concat(parts, ", ")) .. " }"
+    end,
+    _transform = function(self, value, state)
+      local pass, err = types.table(value)
+      if not (pass) then
+        return FailedTransform, err
+      end
+      local check_all = self.check_all
+      local remaining_keys
+      do
+        local _tbl_0 = { }
+        for key in pairs(value) do
+          _tbl_0[key] = true
+        end
+        remaining_keys = _tbl_0
+      end
+      local errors
+      local dirty = false
+      local out = { }
+      for shape_key, shape_val in pairs(self.shape) do
+        local item_value = value[shape_key]
+        if remaining_keys then
+          remaining_keys[shape_key] = nil
+        end
+        local new_val
+        if BaseType:is_base_type(shape_val) then
+          new_val, state = shape_val:_transform(item_value, state)
+        else
+          if shape_val == item_value then
+            new_val, state = item_value, state
+          else
+            new_val, state = FailedTransform, "expected " .. tostring(describe_literal(shape_val))
+          end
+        end
+        if new_val == FailedTransform then
+          err = "field " .. tostring(describe_literal(shape_key)) .. ": " .. tostring(state)
+          if check_all then
+            if errors then
+              table.insert(errors, err)
+            else
+              errors = {
+                err
+              }
+            end
+          else
+            return FailedTransform, err
+          end
+        else
+          if new_val ~= item_value then
+            dirty = true
+          end
+          out[shape_key] = new_val
+        end
+      end
+      if remaining_keys and next(remaining_keys) then
+        if self.open then
+          for k in pairs(remaining_keys) do
+            out[k] = value[k]
+          end
+        elseif self.extra_fields_type then
+          for k in pairs(remaining_keys) do
+            local item_value = value[k]
+            local tuple
+            tuple, state = self.extra_fields_type:_transform({
+              [k] = item_value
+            }, state)
+            if tuple == FailedTransform then
+              err = "field " .. tostring(describe_literal(k)) .. ": " .. tostring(state)
+              if check_all then
+                if errors then
+                  table.insert(errors, err)
+                else
+                  errors = {
+                    err
+                  }
+                end
+              else
+                return FailedTransform, err
+              end
+            else
+              do
+                local nk = tuple and next(tuple)
+                if nk then
+                  if nk ~= k then
+                    dirty = true
+                  elseif tuple[nk] ~= item_value then
+                    dirty = true
+                  end
+                  out[nk] = tuple[nk]
+                else
+                  dirty = true
+                end
+              end
+            end
+          end
+        else
+          local names
+          do
+            local _accum_0 = { }
+            local _len_0 = 1
+            for key in pairs(remaining_keys) do
+              _accum_0[_len_0] = describe_literal(key)
+              _len_0 = _len_0 + 1
+            end
+            names = _accum_0
+          end
+          err = "extra fields: " .. tostring(table.concat(names, ", "))
+          if check_all then
+            if errors then
+              table.insert(errors, err)
+            else
+              errors = {
+                err
+              }
+            end
+          else
+            return FailedTransform, err
+          end
+        end
+      end
+      if errors and next(errors) then
+        return FailedTransform, table.concat(errors, "; ")
+      end
+      return dirty and out or value, state
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, shape, opts)
+      self.shape, self.opts = shape, opts
+      _class_0.__parent.__init(self)
+      assert(type(self.shape) == "table", "expected table for shape")
+      if self.opts then
+        self.extra_fields_type = self.opts.extra_fields
+        self.open = self.opts.open
+        self.check_all = self.opts.check_all
+        if self.open then
+          assert(not self.extra_fields_type, "open can not be combined with extra_fields")
+        end
+        if self.extra_fields_type then
+          return assert(not self.open, "extra_fields can not be combined with open")
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Shape",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.type_err_message = "expecting table"
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Shape = _class_0
+end
+local Pattern
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _describe = function(self)
+      return "pattern " .. tostring(describe_literal(self.pattern))
+    end,
+    _transform = function(self, value, state)
+      do
+        local initial = self.opts and self.opts.initial_type
+        if initial then
+          if not (type(value) == initial) then
+            return FailedTransform, "expected " .. tostring(describe_literal(initial))
+          end
+        end
+      end
+      if self.opts and self.opts.coerce then
+        value = tostring(value)
+      end
+      local t_res, err = types.string(value)
+      if not (t_res) then
+        return FailedTransform, err
+      end
+      if value:match(self.pattern) then
+        return value, state
+      else
+        return FailedTransform, "doesn't match " .. tostring(self:_describe())
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, pattern, opts)
+      self.pattern, self.opts = pattern, opts
+      return _class_0.__parent.__init(self)
+    end,
+    __base = _base_0,
+    __name = "Pattern",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Pattern = _class_0
+end
+local Literal
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _describe = function(self)
+      return describe_literal(self.value)
+    end,
+    _transform = function(self, value, state)
+      if self.value ~= value then
+        return FailedTransform, "expected " .. tostring(self:_describe())
+      end
+      return value, state
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, value, opts)
+      self.value, self.opts = value, opts
+      return _class_0.__parent.__init(self)
+    end,
+    __base = _base_0,
+    __name = "Literal",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Literal = _class_0
+end
+local Custom
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _describe = function(self)
+      return self.opts and self.opts.describe or "custom checker " .. tostring(self.fn)
+    end,
+    _transform = function(self, value, state)
+      local pass, err = self.fn(value, state)
+      if not (pass) then
+        return FailedTransform, err or "failed custom check"
+      end
+      return value, state
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, fn, opts)
+      self.fn, self.opts = fn, opts
+      return _class_0.__parent.__init(self)
+    end,
+    __base = _base_0,
+    __name = "Custom",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Custom = _class_0
+end
+local Equivalent
+do
+  local _class_0
+  local values_equivalent
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _transform = function(self, value, state)
+      if values_equivalent(self.val, value) then
+        return value, state
+      else
+        return FailedTransform, "not equivalent to " .. tostring(self.val)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, val, opts)
+      self.val, self.opts = val, opts
+      return _class_0.__parent.__init(self)
+    end,
+    __base = _base_0,
+    __name = "Equivalent",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  values_equivalent = function(a, b)
+    if a == b then
+      return true
+    end
+    if type(a) == "table" and type(b) == "table" then
+      local seen_keys = { }
+      for k, v in pairs(a) do
+        seen_keys[k] = true
+        if not (values_equivalent(v, b[k])) then
+          return false
+        end
+      end
+      for k, v in pairs(b) do
+        local _continue_0 = false
+        repeat
+          if seen_keys[k] then
+            _continue_0 = true
+            break
+          end
+          if not (values_equivalent(v, a[k])) then
+            return false
+          end
+          _continue_0 = true
+        until true
+        if not _continue_0 then
+          break
+        end
+      end
+      return true
+    else
+      return false
+    end
+  end
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Equivalent = _class_0
+end
+local Range
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _transform = function(self, value, state)
+      local res
+      res, state = self.value_type:_transform(value, state)
+      if res == FailedTransform then
+        return FailedTransform, "range " .. tostring(state)
+      end
+      if value < self.left then
+        return FailedTransform, "not in " .. tostring(self:_describe())
+      end
+      if value > self.right then
+        return FailedTransform, "not in " .. tostring(self:_describe())
+      end
+      return value, state
+    end,
+    _describe = function(self)
+      return "range from " .. tostring(self.left) .. " to " .. tostring(self.right)
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, left, right, opts)
+      self.left, self.right, self.opts = left, right, opts
+      _class_0.__parent.__init(self)
+      assert(self.left <= self.right, "left range value should be less than right range value")
+      self.value_type = assert(types[type(self.left)], "couldn't figure out type of range boundary")
+    end,
+    __base = _base_0,
+    __name = "Range",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Range = _class_0
+end
+local Proxy
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    _transform = function(self, ...)
+      return assert(self.fn(), "proxy missing transformer"):_transform(...)
+    end,
+    _describe = function(self, ...)
+      return assert(self.fn(), "proxy missing transformer"):_describe(...)
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, fn, opts)
+      self.fn, self.opts = fn, opts
+    end,
+    __base = _base_0,
+    __name = "Proxy",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Proxy = _class_0
+end
+types = setmetatable({
+  any = AnyType(),
+  string = Type("string"),
+  number = Type("number"),
+  ["function"] = Type("function"),
+  func = Type("function"),
+  boolean = Type("boolean"),
+  userdata = Type("userdata"),
+  ["nil"] = Type("nil"),
+  table = Type("table"),
+  array = ArrayType(),
+  integer = Pattern("^%d+$", {
+    coerce = true,
+    initial_type = "number"
+  }),
+  one_of = OneOf,
+  all_of = AllOf,
+  shape = Shape,
+  pattern = Pattern,
+  array_of = ArrayOf,
+  map_of = MapOf,
+  literal = Literal,
+  range = Range,
+  equivalent = Equivalent,
+  custom = Custom,
+  scope = TagScopeType,
+  proxy = Proxy
+}, {
+  __index = function(self, fn_name)
+    return error("Type checker does not exist: `" .. tostring(fn_name) .. "`")
+  end
+})
+local check_shape
+check_shape = function(value, shape)
+  assert(shape.check_value, "missing check_value method from shape")
+  return shape:check_value(value)
+end
+local is_type
+is_type = function(val)
+  return BaseType:is_base_type(val)
+end
+local type_switch
+type_switch = function(val)
+  return setmetatable({
+    val
+  }, {
+    __eq = BaseType.__eq
+  })
+end
+return {
+  check_shape = check_shape,
+  types = types,
+  is_type = is_type,
+  type_switch = type_switch,
+  BaseType = BaseType,
+  FailedTransform = FailedTransform,
+  VERSION = "2.0.0"
+}