From 7d3e2bd2c4cfd1296d1d6f996d7548de26540d41 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 15 Feb 2013 16:27:18 -0800 Subject: Sync with 8 months of Google-internal development. Many things have changed and been simplified. The memory-management story for upb_def and upb_handlers is much more robust; upb_def and upb_handlers should be fairly stable interfaces now. There is still much work to do for the runtime component (upb_sink). --- bindings/cpp/upb/bytestream.cc | 39 - bindings/cpp/upb/bytestream.hpp | 276 ------- bindings/cpp/upb/def.hpp | 462 ----------- bindings/cpp/upb/handlers.cc | 39 - bindings/cpp/upb/handlers.hpp | 176 ---- bindings/cpp/upb/msg.hpp | 62 -- bindings/cpp/upb/pb/decoder.hpp | 12 +- bindings/cpp/upb/pb/glue.hpp | 35 - bindings/cpp/upb/proto2_bridge.cc | 892 --------------------- bindings/cpp/upb/proto2_bridge.hpp | 170 ---- bindings/cpp/upb/upb.hpp | 81 -- bindings/linux/Makefile | 4 - bindings/linux/ctype.h | 8 - bindings/linux/inttypes.h | 22 - bindings/linux/setjmp.S | 60 -- bindings/linux/setjmp.h | 13 - bindings/linux/string.h | 13 - bindings/lua/LICENSE | 32 + bindings/lua/lunitx/atexit.lua | 32 + bindings/lua/lunitx/lunit.lua | 725 +++++++++++++++++ bindings/lua/lunitx/lunit/console.lua | 156 ++++ bindings/lua/lunitx/lunitx.lua | 21 + bindings/lua/table.c | 167 ++++ bindings/lua/test.lua | 345 +++++--- bindings/lua/upb.c | 1412 +++++++++++++++++---------------- bindings/lua/upb.h | 45 ++ 26 files changed, 2170 insertions(+), 3129 deletions(-) delete mode 100644 bindings/cpp/upb/bytestream.cc delete mode 100644 bindings/cpp/upb/bytestream.hpp delete mode 100644 bindings/cpp/upb/def.hpp delete mode 100644 bindings/cpp/upb/handlers.cc delete mode 100644 bindings/cpp/upb/handlers.hpp delete mode 100644 bindings/cpp/upb/msg.hpp delete mode 100644 bindings/cpp/upb/pb/glue.hpp delete mode 100644 bindings/cpp/upb/proto2_bridge.cc delete mode 100644 bindings/cpp/upb/proto2_bridge.hpp delete mode 100644 bindings/cpp/upb/upb.hpp delete mode 100644 bindings/linux/ctype.h delete mode 100644 bindings/linux/inttypes.h delete mode 100644 bindings/linux/setjmp.S delete mode 100644 bindings/linux/setjmp.h create mode 100644 bindings/lua/LICENSE create mode 100644 bindings/lua/lunitx/atexit.lua create mode 100644 bindings/lua/lunitx/lunit.lua create mode 100644 bindings/lua/lunitx/lunit/console.lua create mode 100644 bindings/lua/lunitx/lunitx.lua create mode 100644 bindings/lua/table.c create mode 100644 bindings/lua/upb.h (limited to 'bindings') diff --git a/bindings/cpp/upb/bytestream.cc b/bindings/cpp/upb/bytestream.cc deleted file mode 100644 index df0797e..0000000 --- a/bindings/cpp/upb/bytestream.cc +++ /dev/null @@ -1,39 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011 Google Inc. See LICENSE for details. -// Author: Josh Haberman - -#include "bytestream.hpp" - -namespace upb { - -upb_bytesrc_vtbl* ByteSourceBase::vtable() { - static upb_bytesrc_vtbl vtbl = { - &ByteSourceBase::VFetch, - &ByteSourceBase::VDiscard, - &ByteSourceBase::VCopy, - &ByteSourceBase::VGetPtr, - }; - return &vtbl; -} - -upb_bytesuccess_t ByteSourceBase::VFetch(void *src, uint64_t ofs, size_t *len) { - return static_cast(src)->Fetch(ofs, len); -} - -void ByteSourceBase::VCopy( - const void *src, uint64_t ofs, size_t len, char* dest) { - static_cast(src)->Copy(ofs, len, dest); -} - -void ByteSourceBase::VDiscard(void *src, uint64_t ofs) { - static_cast(src)->Discard(ofs); -} - -const char * ByteSourceBase::VGetPtr( - const void *src, uint64_t ofs, size_t* len) { - return static_cast(src)->GetPtr(ofs, len); -} - -} // namespace upb diff --git a/bindings/cpp/upb/bytestream.hpp b/bindings/cpp/upb/bytestream.hpp deleted file mode 100644 index 37d8157..0000000 --- a/bindings/cpp/upb/bytestream.hpp +++ /dev/null @@ -1,276 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011 Google Inc. See LICENSE for details. -// Author: Josh Haberman -// -// This file defines three core interfaces: -// - upb::ByteSink: for writing streams of data. -// - upb::ByteSource: for reading streams of data. -// - upb::ByteRegion: for reading from a specific region of a ByteSource; -// should be used by decoders instead of using a ByteSource directly. -// -// These interfaces are used by streaming encoders and decoders: for example, a -// protobuf parser gets its input from a upb::ByteRegion. They are virtual -// base classes so concrete implementations can get the data from a fd, a -// FILE*, a string, etc. -// -// A ByteRegion represents a region of data from a ByteSource. -// -// Parsers get data from this interface instead of a bytesrc because we often -// want to parse only a specific region of the input. For example, if we parse -// a string from our input but know that the string represents a protobuf, we -// can pass its ByteRegion to an appropriate protobuf parser. -// -// Since the bytes may be coming from a file or network socket, bytes must be -// fetched before they can be read (though in some cases this fetch may be a -// no-op). "fetch" is the only operation on a byteregion that could fail or -// block, because it is the only operation that actually performs I/O. -// -// Bytes can be discarded when they are no longer needed. Parsers should -// always discard bytes they no longer need, both so the buffers can be freed -// when possible and to give better visibility into what bytes the parser is -// still using. -// -// start discard read fetch end -// ofs ofs ofs ofs ofs -// | |--->Discard() | |--->Fetch() | -// V V V V V -// +-------------+-------------------------+-----------------+-----------------+ -// | discarded | | | fetchable | -// +-------------+-------------------------+-----------------+-----------------+ -// | <------------- loaded ------------------> | -// | <- available -> | -// | <---------- remaining ----------> | -// -// Note that the start offset may be something other than zero! A byteregion -// is a view into an underlying bytesrc stream, and the region may start -// somewhere other than the beginning of that stream. -// -// The region can be either delimited or nondelimited. A non-delimited region -// will keep returning data until the underlying data source returns EOF. A -// delimited region will return EOF at a predetermined offset. -// -// end -// ofs -// | -// V -// +-----------------------+ -// | delimited region | <-- hard EOF, even if data source has more data. -// +-----------------------+ -// -// +------------------------ -// | nondelimited region Z <-- won't return EOF until data source hits EOF. -// +------------------------ - -#ifndef UPB_BYTESTREAM_HPP -#define UPB_BYTESTREAM_HPP - -#include "upb/bytestream.h" -#include "upb/upb.hpp" -#include - -namespace upb { - -typedef upb_bytesuccess_t ByteSuccess; - -// Implement this interface to vend bytes to ByteRegions which will be used by -// a decoder. -class ByteSourceBase : public upb_bytesrc { - public: - ByteSourceBase() { upb_bytesrc_init(this, vtable()); } - virtual ~ByteSourceBase() { upb_bytesrc_uninit(this); } - - // Fetches at least one byte starting at ofs, setting *len to the actual - // number of bytes fetched (or 0 on EOF or error: see return value for - // details). It is valid for bytes to be fetched multiple times, as long as - // the bytes have not been previously discarded. - virtual ByteSuccess Fetch(uint64_t ofs, size_t* len) = 0; - - // Discards all data prior to ofs (except data that is pinned, if pinning - // support is added -- see TODO below). - virtual void Discard(uint64_t ofs) = 0; - - // Copies "len" bytes of data from ofs to "dst", which must be at least "len" - // bytes long. The given region must not be discarded. - virtual void Copy(uint64_t ofs, size_t len, char *dst) const = 0; - - // Returns a pointer to the bytesrc's internal buffer, storing in *len how - // much data is available. The given offset must not be discarded. The - // returned buffer is valid for as long as its bytes are not discarded (in - // the case that part of the returned buffer is discarded, only the - // non-discarded bytes remain valid). - virtual const char *GetPtr(uint64_t ofs, size_t *len) const = 0; - - // TODO: Add if/when there is a demonstrated need: - // - // // When the caller pins a region (which must not be already discarded), it - // // is guaranteed that the region will not be discarded (nor will the - // // bytesrc be destroyed) until the region is unpinned. However, not all - // // bytesrc's support pinning; a false return indicates that a pin was not - // // possible. - // virtual bool Pin(uint64_t ofs, size_t len); - // - // // Releases some number of pinned bytes from the beginning of a pinned - // // region (which may be fewer than the total number of bytes pinned). - // virtual void Unpin(uint64_t ofs, size_t len, size_t bytes_to_release); - // - // Adding pinning support would also involve adding a "pin_ofs" parameter to - // upb_bytesrc_fetch, so that the fetch can extend an already-pinned region. - private: - static upb_bytesrc_vtbl* vtable(); - static upb_bytesuccess_t VFetch(void*, uint64_t, size_t*); - static void VDiscard(void*, uint64_t); - static void VCopy(const void*, uint64_t, size_t, char*); - static const char *VGetPtr(const void*, uint64_t, size_t*); -}; - -class ByteRegion : public upb_byteregion { - public: - static const uint64_t kNondelimited = UPB_NONDELIMITED; - - ByteRegion() { upb_byteregion_init(this); } - ~ByteRegion() { upb_byteregion_uninit(this); } - - // Accessors for the regions bounds -- the meaning of these is described in - // the diagram above. - uint64_t start_ofs() const { return upb_byteregion_startofs(this); } - uint64_t discard_ofs() const { return upb_byteregion_discardofs(this); } - uint64_t fetch_ofs() const { return upb_byteregion_fetchofs(this); } - uint64_t end_ofs() const { return upb_byteregion_endofs(this); } - - // Returns how many bytes are fetched and available for reading starting from - // offset "offset". - uint64_t BytesAvailable(uint64_t offset) const { - return upb_byteregion_available(this, offset); - } - - // Returns the total number of bytes remaining after offset "offset", or - // kNondelimited if the byteregion is non-delimited. - uint64_t BytesRemaining(uint64_t offset) const { - return upb_byteregion_remaining(this, offset); - } - - uint64_t Length() const { return upb_byteregion_len(this); } - - // Sets the value of this byteregion to be a subset of the given byteregion's - // data. The caller is responsible for releasing this region before the src - // region is released (unless the region is first pinned, if pinning support - // is added. see below). - void Reset(const upb_byteregion *src, uint64_t ofs, uint64_t len) { - upb_byteregion_reset(this, src, ofs, len); - } - void Release() { upb_byteregion_release(this); } - - // Attempts to fetch more data, extending the fetched range of this - // byteregion. Returns true if the fetched region was extended by at least - // one byte, false on EOF or error (see *s for details). - ByteSuccess Fetch() { return upb_byteregion_fetch(this); } - - // Fetches all remaining data, returning false if the operation failed (see - // *s for details). May only be used on delimited byteregions. - ByteSuccess FetchAll() { return upb_byteregion_fetchall(this); } - - // Discards bytes from the byteregion up until ofs (which must be greater or - // equal to discard_ofs()). It is valid to discard bytes that have not been - // fetched (such bytes will never be fetched) but it is an error to discard - // past the end of a delimited byteregion. - void Discard(uint64_t ofs) { return upb_byteregion_discard(this, ofs); } - - // Copies "len" bytes of data into "dst", starting at ofs. The specified - // region must be available. - void Copy(uint64_t ofs, size_t len, char *dst) const { - upb_byteregion_copy(this, ofs, len, dst); - } - - // Copies all bytes from the byteregion into dst. Requires that the entire - // byteregion is fetched and that none has been discarded. - void CopyAll(char *dst) const { - upb_byteregion_copyall(this, dst); - } - - // Returns a pointer to the internal buffer for the byteregion starting at - // offset "ofs." Stores the number of bytes available in this buffer in *len. - // The returned buffer is invalidated when the byteregion is reset or - // released, or when the bytes are discarded. If the byteregion is not - // currently pinned, the pointer is only valid for the lifetime of the parent - // byteregion. - const char *GetPtr(uint64_t ofs, size_t *len) const { - return upb_byteregion_getptr(this, ofs, len); - } - - // Copies the contents of the byteregion into a newly-allocated, - // NULL-terminated string. Requires that the byteregion is fully fetched. - char *StrDup() const { - return upb_byteregion_strdup(this); - } - - template void AssignToString(T* str) { - uint64_t ofs = start_ofs(); - size_t len; - const char *ptr = GetPtr(ofs, &len); - // Emperically calling reserve() here is counterproductive and slows down - // benchmarks. If the parsing is happening in a tight loop that is reusing - // the string object, there is probably enough data reserved already and - // the reserve() call is extra overhead. - str->assign(ptr, len); - ofs += len; - while (ofs < end_ofs()) { - ptr = GetPtr(ofs, &len); - str->append(ptr, len); - ofs += len; - } - } - - // TODO: add if/when there is a demonstrated need. - // - // // Pins this byteregion's bytes in memory, allowing it to outlive its - // // parent byteregion. Normally a byteregion may only be used while its - // // parent is still valid, but a pinned byteregion may continue to be used - // // until it is reset or released. A byteregion must be fully fetched to - // // be pinned (this implies that the byteregion must be delimited). - // // - // // In some cases this operation may cause the input data to be copied. - // // - // // void Pin(); -}; - -class StringSource : public upb_stringsrc { - public: - StringSource() : upb_stringsrc() { upb_stringsrc_init(this); } - template explicit StringSource(const T& str) { - upb_stringsrc_init(this); - Reset(str); - } - StringSource(const char *data, size_t len) { - upb_stringsrc_init(this); - Reset(data, len); - } - ~StringSource() { upb_stringsrc_uninit(this); } - - void Reset(const char* data, size_t len) { - upb_stringsrc_reset(this, data, len); - } - - template void Reset(const T& str) { - Reset(str.c_str(), str.size()); - } - - ByteRegion* AllBytes() { - return static_cast(upb_stringsrc_allbytes(this)); - } - - upb_bytesrc* ByteSource() { return upb_stringsrc_bytesrc(this); } -}; - -template <> inline ByteRegion* GetValue(Value v) { - return static_cast(upb_value_getbyteregion(v)); -} - -template <> inline Value MakeValue(ByteRegion* v) { - return upb_value_byteregion(v); -} - -} // namespace upb - -#endif diff --git a/bindings/cpp/upb/def.hpp b/bindings/cpp/upb/def.hpp deleted file mode 100644 index 6547255..0000000 --- a/bindings/cpp/upb/def.hpp +++ /dev/null @@ -1,462 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. -// Author: Josh Haberman -// -// The set of upb::*Def classes and upb::SymbolTable allow for defining and -// manipulating schema information (as defined in .proto files). -// -// Defs go through two distinct phases of life: -// -// 1. MUTABLE: when first created, the properties of the def can be set freely -// (for example a message's name, its list of fields, the name/number of -// fields, etc). During this phase the def is *not* thread-safe, and may -// not be used for any purpose except to set its properties (it can't be -// used to parse anything, create any messages in memory, etc). -// -// 2. FINALIZED: the Def::Finzlie() operation finalizes a set of defs, -// which makes them thread-safe and immutable. Finalized defs may only be -// accessed through a CONST POINTER. If you want to modify an existing -// immutable def, copy it with Dup() and modify and finalize the copy. -// -// The refcounting of defs works properly no matter what state the def is in. -// Once the def is finalized it is guaranteed that any def reachable from a -// live def is also live (so a ref on the base of a message tree keeps the -// whole tree alive). -// -// You can test for which stage of life a def is in by calling IsMutable(). -// This is particularly useful for dynamic language bindings, which must -// properly guarantee that the dynamic language cannot break the rules laid out -// above. -// -// It would be possible to make the defs thread-safe during stage 1 by using -// mutexes internally and changing any methods returning pointers to return -// copies instead. This could be important if we are integrating with a VM or -// interpreter that does not naturally serialize access to wrapped objects (for -// example, in the case of Python this is not necessary because of the GIL). - -#ifndef UPB_DEF_HPP -#define UPB_DEF_HPP - -#include -#include -#include -#include "upb/def.h" -#include "upb/upb.hpp" - -namespace upb { - -class Def; -class MessageDef; - -typedef upb_fieldtype_t FieldType; -typedef upb_label_t Label; - -class FieldDef : public upb_fielddef { - public: - static FieldDef* Cast(upb_fielddef *f) { return static_cast(f); } - static const FieldDef* Cast(const upb_fielddef *f) { - return static_cast(f); - } - - static FieldDef* New(const void *owner) { - return Cast(upb_fielddef_new(owner)); - } - FieldDef* Dup(const void *owner) const { - return Cast(upb_fielddef_dup(this, owner)); - } - void Ref(const void *owner) { upb_fielddef_ref(this, owner); } - void Unref(const void *owner) { upb_fielddef_unref(this, owner); } - - bool IsMutable() const { return upb_fielddef_ismutable(this); } - bool IsFinalized() const { return upb_fielddef_isfinalized(this); } - bool IsString() const { return upb_isstring(this); } - bool IsSequence() const { return upb_isseq(this); } - bool IsSubmessage() const { return upb_issubmsg(this); } - - // Simple accessors. ///////////////////////////////////////////////////////// - - FieldType type() const { return upb_fielddef_type(this); } - Label label() const { return upb_fielddef_label(this); } - int32_t number() const { return upb_fielddef_number(this); } - std::string name() const { return std::string(upb_fielddef_name(this)); } - Value default_() const { return upb_fielddef_default(this); } - Value bound_value() const { return upb_fielddef_fval(this); } - uint16_t offset() const { return upb_fielddef_offset(this); } - int16_t hasbit() const { return upb_fielddef_hasbit(this); } - - bool set_type(FieldType type) { return upb_fielddef_settype(this, type); } - bool set_label(Label label) { return upb_fielddef_setlabel(this, label); } - void set_offset(uint16_t offset) { upb_fielddef_setoffset(this, offset); } - void set_hasbit(int16_t hasbit) { upb_fielddef_sethasbit(this, hasbit); } - void set_fval(Value fval) { upb_fielddef_setfval(this, fval); } - void set_accessor(struct _upb_accessor_vtbl* vtbl) { - upb_fielddef_setaccessor(this, vtbl); - } - MessageDef* message(); - const MessageDef* message() const; - - struct _upb_accessor_vtbl *accessor() const { - return upb_fielddef_accessor(this); - } - - // "Number" and "name" must be set before the fielddef is added to a msgdef. - // For the moment we do not allow these to be set once the fielddef is added - // to a msgdef -- this could be relaxed in the future. - bool set_number(int32_t number) { - return upb_fielddef_setnumber(this, number); - } - bool set_name(const char *name) { return upb_fielddef_setname(this, name); } - bool set_name(const std::string& name) { return set_name(name.c_str()); } - - // Default value. //////////////////////////////////////////////////////////// - - // Returns the default value for this fielddef, which may either be something - // the client set explicitly or the "default default" (0 for numbers, empty - // for strings). The field's type indicates the type of the returned value, - // except for enum fields that are still mutable. - // - // For enums the default can be set either numerically or symbolically -- the - // upb_fielddef_default_is_symbolic() function below will indicate which it - // is. For string defaults, the value will be a upb_byteregion which is - // invalidated by any other non-const call on this object. Once the fielddef - // is finalized, symbolic enum defaults are resolved, so finalized enum - // fielddefs always have a default of type int32. - Value defaultval() { return upb_fielddef_default(this); } - - // Sets default value for the field. For numeric types, use - // upb_fielddef_setdefault(), and "value" must match the type of the field. - // For string/bytes types, use upb_fielddef_setdefaultstr(). Enum types may - // use either, since the default may be set either numerically or - // symbolically. - // - // NOTE: May only be called for fields whose type has already been set. - // Also, will be reset to default if the field's type is set again. - void set_default(Value value) { upb_fielddef_setdefault(this, value); } - void set_default(const char *str) { upb_fielddef_setdefaultcstr(this, str); } - void set_default(const char *str, size_t len) { - upb_fielddef_setdefaultstr(this, str, len); - } - void set_default(const std::string& str) { - upb_fielddef_setdefaultstr(this, str.c_str(), str.size()); - } - - // The results of this function are only meaningful for mutable enum fields, - // which can have a default specified either as an integer or as a string. - // If this returns true, the default returned from upb_fielddef_default() is - // a string, otherwise it is an integer. - bool DefaultIsSymbolic() { return upb_fielddef_default_is_symbolic(this); } - - // Subdef. /////////////////////////////////////////////////////////////////// - - // Submessage and enum fields must reference a "subdef", which is the - // MessageDef or EnumDef that defines their type. Note that when the - // FieldDef is mutable it may not have a subdef *yet*, but this still returns - // true to indicate that the field's type requires a subdef. - bool HasSubDef() { return upb_hassubdef(this); } - - // Before a FieldDef is finalized, its subdef may be set either directly - // (with a Def*) or symbolically. Symbolic refs must be resolved by the - // client before the containing msgdef can be finalized. - // - // Both methods require that HasSubDef() (so the type must be set prior to - // calling these methods). Returns false if this is not the case, or if the - // given subdef is not of the correct type. The subtype is reset if the - // field's type is changed. - bool set_subdef(Def* def); - bool set_subtype_name(const char *name) { - return upb_fielddef_setsubtypename(this, name); - } - bool set_subtype_name(const std::string& str) { - return set_subtype_name(str.c_str()); - } - - // Returns the enum or submessage def or symbolic name for this field, if - // any. May only be called for fields where HasSubDef() is true. Returns - // NULL if the subdef has not been set or if you ask for a subtype name when - // the subtype is currently set symbolically (or vice-versa). - // - // Caller does *not* own a ref on the returned def or string. - // subtypename_name() is non-const because only mutable defs can have the - // subtype name set symbolically (symbolic references must be resolved before - // the MessageDef can be finalized). - const Def* subdef() const; - const char *subtype_name() { return upb_fielddef_subtypename(this); } - - private: - UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(FieldDef); -}; - -class Def : public upb_def { - public: - // Converting from C types to C++ wrapper types. - static Def* Cast(upb_def *def) { return static_cast(def); } - static const Def* Cast(const upb_def *def) { - return static_cast(def); - } - - void Ref(const void *owner) const { upb_def_ref(this, owner); } - void Unref(const void *owner) const { upb_def_unref(this, owner); } - - void set_full_name(const char *name) { upb_def_setfullname(this, name); } - void set_full_name(const std::string& name) { - upb_def_setfullname(this, name.c_str()); - } - - const char *full_name() const { return upb_def_fullname(this); } - - // Finalizes the given list of defs (as well as the fielddefs for the given - // msgdefs). All defs reachable from any def in this list must either be - // already finalized or elsewhere in the list. Any symbolic references to - // enums or submessages must already have been resolved. Returns true on - // success, otherwise false is returned and status contains details. In the - // error case the input defs are unmodified. See the comment at the top of - // this file for the semantics of finalized defs. - // - // n is currently limited to 64k defs, if more are required break them into - // batches of 64k (or we could raise this limit, at the cost of a bigger - // upb_def structure or complexity in upb_def_finalize()). - static bool Finalize(Def*const* defs, int n, Status* status) { - return upb_finalize(reinterpret_cast(defs), n, status); - } - static bool Finalize(const std::vector& defs, Status* status) { - return Finalize(&defs[0], defs.size(), status); - } -}; - -class MessageDef : public upb_msgdef { - public: - // Converting from C types to C++ wrapper types. - static MessageDef* Cast(upb_msgdef *md) { - return static_cast(md); - } - static const MessageDef* Cast(const upb_msgdef *md) { - return static_cast(md); - } - static MessageDef* DynamicCast(Def* def) { - return Cast(upb_dyncast_msgdef(def)); - } - static const MessageDef* DynamicCast(const Def* def) { - return Cast(upb_dyncast_msgdef_const(def)); - } - - Def* AsDef() { return Def::Cast(UPB_UPCAST(this)); } - const Def* AsDef() const { return Def::Cast(UPB_UPCAST(this)); } - - static MessageDef* New(void *owner) { return Cast(upb_msgdef_new(owner)); } - MessageDef* Dup(void *owner) const { - return Cast(upb_msgdef_dup(this, owner)); - } - - void Ref(const void *owner) const { upb_msgdef_ref(this, owner); } - void Unref(const void *owner) const { upb_msgdef_unref(this, owner); } - - // Read accessors -- may be called at any time. - - const char *full_name() const { return AsDef()->full_name(); } - - // The total size of in-memory messages created with this MessageDef. - uint16_t instance_size() const { return upb_msgdef_size(this); } - - // The number of "hasbit" bytes in a message instance. - uint8_t hasbit_bytes() const { return upb_msgdef_hasbit_bytes(this); } - - uint32_t extension_start() const { return upb_msgdef_extstart(this); } - uint32_t extension_end() const { return upb_msgdef_extend(this); } - - // Write accessors. May only be called before the msgdef is in a symtab. - - void set_full_name(const char *name) { AsDef()->set_full_name(name); } - void set_full_name(const std::string& name) { AsDef()->set_full_name(name); } - - void set_instance_size(uint16_t size) { upb_msgdef_setsize(this, size); } - void set_hasbit_bytes(uint16_t size) { upb_msgdef_setsize(this, size); } - bool SetExtensionRange(uint32_t start, uint32_t end) { - return upb_msgdef_setextrange(this, start, end); - } - - // Adds a set of fields (FieldDef objects) to a MessageDef. Caller passes a - // ref on the FieldDef to the MessageDef in both success and failure cases. - // May only be done before the MessageDef is in a SymbolTable (requires - // m->IsMutable() for the MessageDef). The FieldDef's name and number must - // be set, and the message may not already contain any field with this name - // or number, and this FieldDef may not be part of another message, otherwise - // false is returned and the MessageDef is unchanged. - bool AddField(FieldDef* f, const void *owner) { - return AddFields(&f, 1, owner); - } - bool AddFields(FieldDef*const * f, int n, const void *owner) { - return upb_msgdef_addfields(this, (upb_fielddef*const*)f, n, owner); - } - bool AddFields(const std::vector& fields, const void *owner) { - return AddFields(&fields[0], fields.size(), owner); - } - - int field_count() const { return upb_msgdef_numfields(this); } - - // Lookup fields by name or number, returning NULL if no such field exists. - FieldDef* FindFieldByName(const char *name) { - return FieldDef::Cast(upb_msgdef_ntof(this, name)); - } - FieldDef* FindFieldByName(const std::string& name) { - return FieldDef::Cast(upb_msgdef_ntof(this, name.c_str())); - } - FieldDef* FindFieldByNumber(uint32_t num) { - return FieldDef::Cast(upb_msgdef_itof(this, num)); - } - - const FieldDef* FindFieldByName(const char *name) const { - return FindFieldByName(name); - } - const FieldDef* FindFieldByName(const std::string& name) const { - return FindFieldByName(name); - } - const FieldDef* FindFieldByNumber(uint32_t num) const { - return FindFieldByNumber(num); - } - - class Iterator : public upb_msg_iter { - public: - explicit Iterator(MessageDef* md) { upb_msg_begin(this, md); } - Iterator() {} - - FieldDef* field() { return FieldDef::Cast(upb_msg_iter_field(this)); } - bool Done() { return upb_msg_done(this); } - void Next() { return upb_msg_next(this); } - }; - - class ConstIterator : public upb_msg_iter { - public: - explicit ConstIterator(const MessageDef* md) { upb_msg_begin(this, md); } - ConstIterator() {} - - const FieldDef* field() { return FieldDef::Cast(upb_msg_iter_field(this)); } - bool Done() { return upb_msg_done(this); } - void Next() { return upb_msg_next(this); } - }; - - private: - UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(MessageDef); -}; - -class EnumDef : public upb_enumdef { - public: - // Converting from C types to C++ wrapper types. - static EnumDef* Cast(upb_enumdef *e) { return static_cast(e); } - static const EnumDef* Cast(const upb_enumdef *e) { - return static_cast(e); - } - - static EnumDef* New(const void *owner) { return Cast(upb_enumdef_new(owner)); } - - void Ref(const void *owner) { upb_enumdef_ref(this, owner); } - void Unref(const void *owner) { upb_enumdef_unref(this, owner); } - EnumDef* Dup(const void *owner) const { - return Cast(upb_enumdef_dup(this, owner)); - } - - Def* AsDef() { return Def::Cast(UPB_UPCAST(this)); } - const Def* AsDef() const { return Def::Cast(UPB_UPCAST(this)); } - - int32_t default_value() const { return upb_enumdef_default(this); } - - // May only be set if IsMutable(). - void set_full_name(const char *name) { AsDef()->set_full_name(name); } - void set_full_name(const std::string& name) { AsDef()->set_full_name(name); } - void set_default_value(int32_t val) { - return upb_enumdef_setdefault(this, val); - } - - // Adds a value to the enumdef. Requires that no existing val has this - // name or number (returns false and does not add if there is). May only - // be called if IsMutable(). - bool AddValue(char *name, int32_t num) { - return upb_enumdef_addval(this, name, num); - } - bool AddValue(const std::string& name, int32_t num) { - return upb_enumdef_addval(this, name.c_str(), num); - } - - // Lookups from name to integer and vice-versa. - bool LookupName(const char *name, int32_t* num) const { - return upb_enumdef_ntoi(this, name, num); - } - - // Lookup from integer to name, returns a NULL-terminated string which - // the caller does not own, or NULL if not found. - const char *LookupNumber(int32_t num) const { - return upb_enumdef_iton(this, num); - } - - private: - UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(EnumDef); -}; - -class SymbolTable : public upb_symtab { - public: - // Converting from C types to C++ wrapper types. - static SymbolTable* Cast(upb_symtab *s) { - return static_cast(s); - } - static const SymbolTable* Cast(const upb_symtab *s) { - return static_cast(s); - } - - static SymbolTable* New(const void *owner) { - return Cast(upb_symtab_new(owner)); - } - - void Ref(const void *owner) const { upb_symtab_unref(this, owner); } - void Unref(const void *owner) const { upb_symtab_unref(this, owner); } - void DonateRef(const void *from, const void *to) const { - upb_symtab_donateref(this, from, to); - } - - // Adds the given defs to the symtab, resolving all symbols. Only one def - // per name may be in the list, but defs can replace existing defs in the - // symtab. The entire operation either succeeds or fails. If the operation - // fails, the symtab is unchanged, false is returned, and status indicates - // the error. The caller passes a ref on the defs in all cases. - bool Add(Def *const *defs, int n, void *owner, Status* status) { - return upb_symtab_add(this, (upb_def*const*)defs, n, owner, status); - } - bool Add(const std::vector& defs, void *owner, Status* status) { - return Add(&defs[0], defs.size(), owner, status); - } - - // If the given name refers to a message in this symbol table, returns a new - // ref to that MessageDef object, otherwise returns NULL. - const MessageDef* LookupMessage(const char *name, void *owner) const { - return MessageDef::Cast(upb_symtab_lookupmsg(this, name, owner)); - } - - private: - UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(SymbolTable); -}; - -template <> inline const FieldDef* GetValue(Value v) { - return static_cast(upb_value_getfielddef(v)); -} - -template <> inline Value MakeValue(FieldDef* v) { - return upb_value_fielddef(v); -} - -inline MessageDef* FieldDef::message() { - return MessageDef::Cast(upb_fielddef_msgdef(this)); -} -inline const MessageDef* FieldDef::message() const { - return MessageDef::Cast(upb_fielddef_msgdef(this)); -} - -inline const Def* FieldDef::subdef() const { - return Def::Cast(upb_fielddef_subdef(this)); -} -inline bool FieldDef::set_subdef(Def* def) { - return upb_fielddef_setsubdef(this, def); -} - -} // namespace upb - -#endif diff --git a/bindings/cpp/upb/handlers.cc b/bindings/cpp/upb/handlers.cc deleted file mode 100644 index c96a74e..0000000 --- a/bindings/cpp/upb/handlers.cc +++ /dev/null @@ -1,39 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011 Google Inc. See LICENSE for details. -// Author: Josh Haberman - -#include "handlers.hpp" - -#include "def.hpp" - -namespace upb { - -namespace { - -void MessageCallbackWrapper( - void* closure, upb_mhandlers* mh, const upb_msgdef* m) { - Handlers::MessageRegistrationVisitor* visitor = - static_cast(closure); - visitor->OnMessage(static_cast(mh), - static_cast(m)); -} - -void FieldCallbackWrapper( - void* closure, upb_fhandlers* fh, const upb_fielddef* f) { - Handlers::MessageRegistrationVisitor* visitor = - static_cast(closure); - visitor->OnField(static_cast(fh), - static_cast(f)); -} -} // namepace - -MessageHandlers* Handlers::RegisterMessageDef( - const MessageDef& m, Handlers::MessageRegistrationVisitor* visitor) { - upb_mhandlers* mh = upb_handlers_regmsgdef( - this, &m, &MessageCallbackWrapper, &FieldCallbackWrapper, &visitor); - return static_cast(mh); -} - -} // namespace upb diff --git a/bindings/cpp/upb/handlers.hpp b/bindings/cpp/upb/handlers.hpp deleted file mode 100644 index a366c3d..0000000 --- a/bindings/cpp/upb/handlers.hpp +++ /dev/null @@ -1,176 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011 Google Inc. See LICENSE for details. -// Author: Josh Haberman -// -// upb::Handlers is a generic visitor-like interface for iterating over a -// stream of protobuf data. You can register function pointers that will be -// called for each message and/or field as the data is being parsed or iterated -// over, without having to know the source format that we are parsing from. -// This decouples the parsing logic from the processing logic. - -#ifndef UPB_HANDLERS_HPP -#define UPB_HANDLERS_HPP - -#include "upb/handlers.h" - -#include "upb/upb.hpp" - -namespace upb { - -typedef upb_fieldtype_t FieldType; -typedef upb_flow_t Flow; -typedef upb_sflow_t SubFlow; -class MessageHandlers; -class MessageDef; -class FieldDef; - -class FieldHandlers : public upb_fhandlers { - public: - typedef upb_value_handler ValueHandler; - typedef upb_startfield_handler StartFieldHandler; - typedef upb_endfield_handler EndFieldHandler; - - // The FieldHandlers will live at least as long as the upb::Handlers to - // which it belongs, but can be Ref'd/Unref'd to make it live longer (which - // will prolong the life of the underlying upb::Handlers also). - void Ref() { upb_fhandlers_ref(this); } - void Unref() { upb_fhandlers_unref(this); } - - // Functions to set this field's handlers. - // These return "this" so they can be conveniently chained, eg. - // message_handlers->NewField(...) - // ->SetStartSequenceHandler(&StartSequence), - // ->SetEndSequenceHandler(&EndSequence), - // ->SetValueHandler(&Value); - FieldHandlers* SetValueHandler(ValueHandler* h) { - upb_fhandlers_setvalue(this, h); return this; - } - FieldHandlers* SetStartSequenceHandler(StartFieldHandler* h) { - upb_fhandlers_setstartseq(this, h); return this; - } - FieldHandlers* SetEndSequenceHandler(EndFieldHandler* h) { - upb_fhandlers_setendseq(this, h); return this; - } - FieldHandlers* SetStartSubmessageHandler(StartFieldHandler* h) { - upb_fhandlers_setstartsubmsg(this, h); return this; - } - FieldHandlers* SetEndSubmessageHandler(EndFieldHandler* h) { - upb_fhandlers_setendsubmsg(this, h); return this; - } - - // Get/Set the field's bound value, which will be passed to its handlers. - Value GetBoundValue() const { return upb_fhandlers_getfval(this); } - FieldHandlers* SetBoundValue(Value val) { - upb_fhandlers_setfval(this, val); return this; - } - - // Returns the MessageHandlers to which we belong. - MessageHandlers* GetMessageHandlers() const; - // Returns the MessageHandlers for this field's submessage (invalid to call - // unless this field's type UPB_TYPE(MESSAGE) or UPB_TYPE(GROUP). - MessageHandlers* GetSubMessageHandlers() const; - // If set to >=0, the given hasbit will be set after the value callback is - // called (offset relative to the current closure). - int32_t GetHasbit() const { return upb_fhandlers_gethasbit(this); } - void SetHasbit(int32_t bit) { upb_fhandlers_sethasbit(this, bit); } - - private: - UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(FieldHandlers); -}; - -class MessageHandlers : public upb_mhandlers { - public: - typedef upb_startmsg_handler StartMessageHandler; - typedef upb_endmsg_handler EndMessageHandler; - - static MessageHandlers* Cast(upb_mhandlers* mh) { - return static_cast(mh); - } - static const MessageHandlers* Cast(const upb_mhandlers* mh) { - return static_cast(mh); - } - - // The MessageHandlers will live at least as long as the upb::Handlers to - // which it belongs, but can be Ref'd/Unref'd to make it live longer (which - // will prolong the life of the underlying upb::Handlers also). - void Ref() { upb_mhandlers_ref(this); } - void Unref() { upb_mhandlers_unref(this); } - - // Functions to set this message's handlers. - // These return "this" so they can be conveniently chained, eg. - // handlers->NewMessageHandlers() - // ->SetStartMessageHandler(&StartMessage) - // ->SetEndMessageHandler(&EndMessage); - MessageHandlers* SetStartMessageHandler(StartMessageHandler* h) { - upb_mhandlers_setstartmsg(this, h); return this; - } - MessageHandlers* SetEndMessageHandler(EndMessageHandler* h) { - upb_mhandlers_setendmsg(this, h); return this; - } - - // Functions to create new FieldHandlers for this message. - FieldHandlers* NewFieldHandlers(uint32_t fieldnum, FieldType type, - bool repeated) { - return static_cast( - upb_mhandlers_newfhandlers(this, fieldnum, type, repeated)); - } - - // Like the previous but for MESSAGE or GROUP fields. For GROUP fields, the - // given submessage must not have any fields with this field number. - FieldHandlers* NewFieldHandlersForSubmessage(uint32_t n, const char *name, - FieldType type, bool repeated, - MessageHandlers* subm) { - (void)name; - return static_cast( - upb_mhandlers_newfhandlers_subm(this, n, type, repeated, subm)); - } - - private: - UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(MessageHandlers); -}; - -class Handlers : public upb_handlers { - public: - // Creates a new Handlers instance. - static Handlers* New() { return static_cast(upb_handlers_new()); } - - void Ref() { upb_handlers_ref(this); } - void Unref() { upb_handlers_unref(this); } - - // Returns a new MessageHandlers object. The first such message that is - // obtained will be the top-level message for this Handlers object. - MessageHandlers* NewMessageHandlers() { - return static_cast(upb_handlers_newmhandlers(this)); - } - - // Convenience function for registering handlers for all messages and fields - // in a MessageDef and all its children. For every registered message, - // OnMessage will be called on the visitor with newly-created MessageHandlers - // and MessageDef. Likewise with OnField will be called with newly-created - // FieldHandlers and FieldDef for each field. - class MessageRegistrationVisitor { - public: - virtual ~MessageRegistrationVisitor() {} - virtual void OnMessage(MessageHandlers* mh, const MessageDef* m) = 0; - virtual void OnField(FieldHandlers* fh, const FieldDef* f) = 0; - }; - MessageHandlers* RegisterMessageDef(const MessageDef& m, - MessageRegistrationVisitor* visitor); - - private: - UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(Handlers); -}; - -inline MessageHandlers* FieldHandlers::GetMessageHandlers() const { - return static_cast(upb_fhandlers_getmsg(this)); -} - -inline MessageHandlers* FieldHandlers::GetSubMessageHandlers() const { - return static_cast(upb_fhandlers_getsubmsg(this)); -} - -} // namespace upb - -#endif diff --git a/bindings/cpp/upb/msg.hpp b/bindings/cpp/upb/msg.hpp deleted file mode 100644 index cde1743..0000000 --- a/bindings/cpp/upb/msg.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011 Google Inc. See LICENSE for details. -// Author: Josh Haberman -// Routines for reading and writing message data to an in-memory structure, -// similar to a C struct. -// -// upb does not define one single message object that everyone must use. -// Rather it defines an abstract interface for reading and writing members -// of a message object, and all of the parsers and serializers use this -// abstract interface. This allows upb's parsers and serializers to be used -// regardless of what memory management scheme or synchronization model the -// application is using. -// -// A standard set of accessors is provided for doing simple reads and writes at -// a known offset into the message. These accessors should be used when -// possible, because they are specially optimized -- for example, the JIT can -// recognize them and emit specialized code instead of having to call the -// function at all. The application can substitute its own accessors when the -// standard accessors are not suitable. - -#ifndef UPB_MSG_HPP -#define UPB_MSG_HPP - -#include "upb/msg.h" -#include "upb/handlers.hpp" - -namespace upb { - -typedef upb_accessor_vtbl AccessorVTable; - -// Registers handlers for writing into a message of the given type using -// whatever accessors it has defined. -inline MessageHandlers* RegisterWriteHandlers(upb::Handlers* handlers, - const upb::MessageDef* md) { - return MessageHandlers::Cast( - upb_accessors_reghandlers(handlers, md)); -} - -template static FieldHandlers::ValueHandler* GetValueHandler(); - -// A handy templated function that will retrieve a value handler for a given -// C++ type. -#define GET_VALUE_HANDLER(type, ctype) \ - template <> \ - inline FieldHandlers::ValueHandler* GetValueHandler() { \ - return &upb_stdmsg_set ## type; \ - } - -GET_VALUE_HANDLER(double, double); -GET_VALUE_HANDLER(float, float); -GET_VALUE_HANDLER(uint64, uint64_t); -GET_VALUE_HANDLER(uint32, uint32_t); -GET_VALUE_HANDLER(int64, int64_t); -GET_VALUE_HANDLER(int32, int32_t); -GET_VALUE_HANDLER(bool, bool); -#undef GET_VALUE_HANDLER - -} // namespace - -#endif diff --git a/bindings/cpp/upb/pb/decoder.hpp b/bindings/cpp/upb/pb/decoder.hpp index 05bcb8a..950e9e2 100644 --- a/bindings/cpp/upb/pb/decoder.hpp +++ b/bindings/cpp/upb/pb/decoder.hpp @@ -22,14 +22,14 @@ #include "upb/pb/decoder.h" -#include "upb/bytestream.hpp" -#include "upb/upb.hpp" +#include "upb/bytestream.h" +#include "upb/upb.h" namespace upb { class DecoderPlan : public upb_decoderplan { public: - static DecoderPlan* New(Handlers* h, bool allow_jit) { + static DecoderPlan* New(const Handlers* h, bool allow_jit) { return static_cast(upb_decoderplan_new(h, allow_jit)); } void Unref() { upb_decoderplan_unref(this); } @@ -54,9 +54,7 @@ class Decoder : public upb_decoder { // reset to a different plan. // // Must be called before ResetInput() or Decode(). - void ResetPlan(DecoderPlan* plan, int32_t msg_offset) { - upb_decoder_resetplan(this, plan, msg_offset); - } + void ResetPlan(DecoderPlan* plan) { upb_decoder_resetplan(this, plan); } // Resets the input of the decoder. This puts it in a state where it has not // seen any data, and expects the next data to be from the beginning of a new @@ -71,7 +69,7 @@ class Decoder : public upb_decoder { // Decodes serialized data (calling Handlers as the data is parsed) until // error or EOF (see status() for details). - Success Decode() { return upb_decoder_decode(this); } + Status::Success Decode() { return upb_decoder_decode(this); } const upb::Status& status() { return static_cast(*upb_decoder_status(this)); diff --git a/bindings/cpp/upb/pb/glue.hpp b/bindings/cpp/upb/pb/glue.hpp deleted file mode 100644 index d43baeb..0000000 --- a/bindings/cpp/upb/pb/glue.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2011 Google Inc. See LICENSE for details. - * Author: Josh Haberman - */ - -#ifndef UPB_PB_GLUE_HPP -#define UPB_PB_GLUE_HPP - -#include "upb/upb.hpp" -#include "upb/pb/glue.h" - -namespace upb { - -// All routines that load descriptors expect the descriptor to be a -// FileDescriptorSet. -bool LoadDescriptorFileIntoSymtab(SymbolTable* s, const char *fname, - Status* status) { - return upb_load_descriptor_file_into_symtab(s, fname, status); -} - -bool LoadDescriptorIntoSymtab(SymbolTable* s, const char* str, - size_t len, Status* status) { - return upb_load_descriptor_into_symtab(s, str, len, status); -} - -template -bool LoadDescriptorIntoSymtab(SymbolTable* s, const T& desc, Status* status) { - return upb_load_descriptor_into_symtab(s, desc.c_str(), desc.size(), status); -} - -} // namespace upb - -#endif diff --git a/bindings/cpp/upb/proto2_bridge.cc b/bindings/cpp/upb/proto2_bridge.cc deleted file mode 100644 index 6119295..0000000 --- a/bindings/cpp/upb/proto2_bridge.cc +++ /dev/null @@ -1,892 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. -// Author: Josh Haberman - -#include -#include -#include "upb/bytestream.hpp" -#include "upb/def.hpp" -#include "upb/handlers.hpp" -#include "upb/msg.hpp" -#include "upb/proto2_bridge.hpp" - -namespace { - -static void* GetFieldPointer(void *message, const upb::FieldDef* f) { - return static_cast(message) + f->offset(); -} - -} // namespace - -#ifdef UPB_GOOGLE3 - -// TODO(haberman): friend upb so that this isn't required. -#define protected public -#include "net/proto2/public/repeated_field.h" -#undef private - -#define private public -#include "net/proto/proto2_reflection.h" -#undef private - -#include "net/proto2/proto/descriptor.pb.h" -#include "net/proto2/public/descriptor.h" -#include "net/proto2/public/generated_message_reflection.h" -#include "net/proto2/public/lazy_field.h" -#include "net/proto2/public/message.h" -#include "net/proto2/public/string_piece_field_support.h" -#include "net/proto/internal_layout.h" -#include "strings/cord.h" -using ::proto2::Descriptor; -using ::proto2::EnumDescriptor; -using ::proto2::EnumValueDescriptor; -using ::proto2::FieldDescriptor; -using ::proto2::FieldOptions; -using ::proto2::FileDescriptor; -using ::proto2::internal::GeneratedMessageReflection; -using ::proto2::internal::RepeatedPtrFieldBase; -using ::proto2::internal::StringPieceField; -using ::proto2::Message; -using ::proto2::MessageFactory; -using ::proto2::Reflection; -using ::proto2::RepeatedField; -using ::proto2::RepeatedPtrField; - -namespace upb { - -static const Message* GetPrototypeForField(const Message& m, - const FieldDescriptor* f); - -namespace proto2_bridge_google3 { class FieldAccessor; } - -using ::upb::proto2_bridge_google3::FieldAccessor; - -namespace proto2_bridge_google3 { - -static void AssignToCord(const ByteRegion* r, Cord* cord) { - // TODO(haberman): ref source data if source is a cord. - cord->Clear(); - uint64_t ofs = r->start_ofs(); - while (ofs < r->end_ofs()) { - size_t len; - const char *buf = r->GetPtr(ofs, &len); - cord->Append(StringPiece(buf, len)); - ofs += len; - } -} - -#else - -// TODO(haberman): friend upb so that this isn't required. -#define protected public -#include "google/protobuf/repeated_field.h" -#undef protected - -#define private public -#include "google/protobuf/generated_message_reflection.h" -#undef private - -#include "google/protobuf/descriptor.h" -#include "google/protobuf/descriptor.pb.h" -#include "google/protobuf/message.h" -using ::google::protobuf::Descriptor; -using ::google::protobuf::EnumDescriptor; -using ::google::protobuf::EnumValueDescriptor; -using ::google::protobuf::FieldDescriptor; -using ::google::protobuf::FieldOptions; -using ::google::protobuf::FileDescriptor; -using ::google::protobuf::internal::GeneratedMessageReflection; -using ::google::protobuf::internal::RepeatedPtrFieldBase; -using ::google::protobuf::Message; -using ::google::protobuf::MessageFactory; -using ::google::protobuf::Reflection; -using ::google::protobuf::RepeatedField; -using ::google::protobuf::RepeatedPtrField; - -namespace upb { -static const Message* GetPrototypeForField(const Message& m, - const FieldDescriptor* f); - -namespace proto2_bridge_opensource { class FieldAccessor; } - -using ::upb::proto2_bridge_opensource::FieldAccessor; - -namespace proto2_bridge_opensource { - -#endif // ifdef UPB_GOOGLE3 - -// Have to define this manually since older versions of proto2 didn't define -// an enum value for STRING. -#define UPB_CTYPE_STRING 0 - -// The code in this class depends on the internal representation of the proto2 -// generated classes, which is an internal implementation detail of proto2 and -// is not a public interface. As a result, this class's implementation may -// need to be changed if/when proto2 changes its internal representation. It -// is intended that this class is the only code that depends on these internal, -// non-public interfaces. -// -// This class only works with messages that use GeneratedMessageReflection. -// Other reflection classes will need other accessor implementations. -class FieldAccessor { - public: - // Returns true if we were able to set an accessor and any other properties - // of the FieldDef that are necessary to read/write this field to a - // proto2::Message. - static bool TrySet(const FieldDescriptor* proto2_f, - const upb::MessageDef* md, - upb::FieldDef* upb_f) { - const Message* prototype = static_cast(md->prototype); - const Reflection* base_r = prototype->GetReflection(); - const GeneratedMessageReflection* r = - dynamic_cast(base_r); - // Old versions of the open-source protobuf release erroneously default to - // Cord even though that has never been supported in the open-source - // release. - int32_t ctype = proto2_f->options().has_ctype() ? - proto2_f->options().ctype() : UPB_CTYPE_STRING; - if (!r) return false; - // Extensions not supported yet. - if (proto2_f->is_extension()) return false; - - upb_f->set_accessor(GetForFieldDescriptor(proto2_f, ctype)); - upb_f->set_hasbit(GetHasbit(proto2_f, r)); - upb_f->set_offset(GetOffset(proto2_f, r)); - if (upb_f->IsSubmessage()) { - upb_f->set_subtype_name(proto2_f->message_type()->full_name()); - upb_f->prototype = GetPrototypeForField(*prototype, proto2_f); - } - - if (upb_f->IsString() && !upb_f->IsSequence() && - ctype == UPB_CTYPE_STRING) { - upb_f->prototype = &r->GetStringReference(*prototype, proto2_f, NULL); - } - return true; - } - - static MessageFactory* GetMessageFactory(const Message& m) { - const GeneratedMessageReflection* r = - dynamic_cast(m.GetReflection()); - return r ? r->message_factory_ : NULL; - } - - private: - static int64_t GetHasbit(const FieldDescriptor* f, - const GeneratedMessageReflection* r) { - if (f->is_repeated()) { - // proto2 does not store hasbits for repeated fields. - return -1; - } else { - return (r->has_bits_offset_ * 8) + f->index(); - } - } - - static uint16_t GetOffset(const FieldDescriptor* f, - const GeneratedMessageReflection* r) { - return r->offsets_[f->index()]; - } - - static AccessorVTable *GetForFieldDescriptor(const FieldDescriptor* f, - int32_t ctype) { - switch (f->cpp_type()) { - case FieldDescriptor::CPPTYPE_ENUM: - // Should handlers validate enum membership to match proto2? - case FieldDescriptor::CPPTYPE_INT32: return Get(); - case FieldDescriptor::CPPTYPE_INT64: return Get(); - case FieldDescriptor::CPPTYPE_UINT32: return Get(); - case FieldDescriptor::CPPTYPE_UINT64: return Get(); - case FieldDescriptor::CPPTYPE_DOUBLE: return Get(); - case FieldDescriptor::CPPTYPE_FLOAT: return Get(); - case FieldDescriptor::CPPTYPE_BOOL: return Get(); - case FieldDescriptor::CPPTYPE_STRING: - switch (ctype) { -#ifdef UPB_GOOGLE3 - case FieldOptions::STRING: - return GetForString(); - case FieldOptions::CORD: - return GetForCord(); - case FieldOptions::STRING_PIECE: - return GetForStringPiece(); -#else - case UPB_CTYPE_STRING: - return GetForString(); -#endif - default: return NULL; - } - case FieldDescriptor::CPPTYPE_MESSAGE: -#ifdef UPB_GOOGLE3 - if (f->options().lazy()) { - return NULL; // Not yet implemented. - } else { - return GetForMessage(); - } -#else - return GetForMessage(); -#endif - default: return NULL; - } - } - - // PushOffset handler (used for StartSequence and others) /////////////////// - - static SubFlow PushOffset(void *m, Value fval) { - const FieldDef *f = GetValue(fval); - return UPB_CONTINUE_WITH(GetFieldPointer(m, f)); - } - - // Primitive Value (numeric, enum, bool) ///////////////////////////////////// - - template static AccessorVTable *Get() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - GetValueHandler(), - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &Append, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - template - static Flow Append(void *_r, Value fval, Value val) { - (void)fval; - RepeatedField* r = static_cast*>(_r); - r->Add(GetValue(val)); - return UPB_CONTINUE; - } - - // String //////////////////////////////////////////////////////////////////// - - template static AccessorVTable *GetForString() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - &SetString, - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &AppendString, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - // This needs to be templated because google3 string is not std::string. - template static Flow SetString(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - T **str = static_cast(GetFieldPointer(m, f)); - // If it points to the default instance, we must create a new instance. - if (*str == f->prototype) *str = new T(); - GetValue(val)->AssignToString(*str); - return UPB_CONTINUE; - } - - template - static Flow AppendString(void *_r, Value fval, Value val) { - (void)fval; - RepeatedPtrField* r = static_cast*>(_r); - GetValue(val)->AssignToString(r->Add()); - return UPB_CONTINUE; - } - - // SubMessage //////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForMessage() { - static upb_accessor_vtbl vtbl = { - &StartSubMessage, - NULL, // Value handler - &PushOffset, // StartSequence handler - &StartRepeatedSubMessage, - NULL, // Repeated value handler - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static SubFlow StartSubMessage(void *m, Value fval) { - const FieldDef* f = GetValue(fval); - void **subm = static_cast(GetFieldPointer(m, f)); - if (*subm == NULL || *subm == f->prototype) { - const Message* prototype = static_cast(f->prototype); - *subm = prototype->New(); - } - return UPB_CONTINUE_WITH(*subm); - } - - class RepeatedMessageTypeHandler { - public: - typedef void Type; - // AddAllocated() calls this, but only if other objects are sitting - // around waiting for reuse, which we will not do. - static void Delete(Type* t) { - (void)t; - assert(false); - } - }; - - // Closure is a RepeatedPtrField*, but we access it through - // its base class RepeatedPtrFieldBase*. - static SubFlow StartRepeatedSubMessage(void* _r, Value fval) { - const FieldDef* f = GetValue(fval); - RepeatedPtrFieldBase *r = static_cast(_r); - void *submsg = r->AddFromCleared(); - if (!submsg) { - const Message* prototype = static_cast(f->prototype); - submsg = prototype->New(); - r->AddAllocated(submsg); - } - return UPB_CONTINUE_WITH(submsg); - } - - // TODO(haberman): handle Extensions, Unknown Fields. - -#ifdef UPB_GOOGLE3 - // Handlers for types/features only included in internal proto2 release: - // Cord, StringPiece, LazyField, and MessageSet. - // TODO(haberman): LazyField, MessageSet. - - // Cord ////////////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForCord() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - &SetCord, - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &AppendCord, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static Flow SetCord(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - Cord* field = static_cast(GetFieldPointer(m, f)); - AssignToCord(GetValue(val), field); - return UPB_CONTINUE; - } - - static Flow AppendCord(void *_r, Value fval, Value val) { - RepeatedField* r = static_cast*>(_r); - AssignToCord(GetValue(val), r->Add()); - return UPB_CONTINUE; - } - - // StringPiece /////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForStringPiece() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - &SetStringPiece, - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &AppendStringPiece, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static void AssignToStringPieceField(const ByteRegion* r, - proto2::internal::StringPieceField* f) { - // TODO(haberman): alias if possible and enabled on the input stream. - // TODO(haberman): add a method to StringPieceField that lets us avoid - // this copy/malloc/free. - char *data = new char[r->Length()]; - r->Copy(r->start_ofs(), r->Length(), data); - f->CopyFrom(StringPiece(data, r->Length())); - delete[] data; - } - - static Flow SetStringPiece(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - StringPieceField* field = - static_cast(GetFieldPointer(m, f)); - AssignToStringPieceField(GetValue(val), field); - return UPB_CONTINUE; - } - - static Flow AppendStringPiece(void* _r, Value fval, Value val) { - RepeatedPtrField* r = - static_cast*>(_r); - AssignToStringPieceField(GetValue(val), r->Add()); - return UPB_CONTINUE; - } - -#endif // UPB_GOOGLE3 -}; - -#ifdef UPB_GOOGLE3 - -// Proto1 accessor -- only needed inside Google. -class Proto1FieldAccessor { - public: - // Returns true if we were able to set an accessor and any other properties - // of the FieldDef that are necessary to read/write this field to a - // proto2::Message. - static bool TrySet(const FieldDescriptor* proto2_f, - const upb::MessageDef* md, - upb::FieldDef* upb_f) { - const Message* m = static_cast(md->prototype); - const proto2::Reflection* base_r = m->GetReflection(); - const _pi::Proto2Reflection* r = - dynamic_cast(base_r); - if (!r) return false; - // Extensions not supported yet. - if (proto2_f->is_extension()) return false; - - const _pi::Field* f = r->GetFieldLayout(proto2_f); - - if (f->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK) { - // Override the BYTES type that proto2 descriptors have for weak fields. - upb_f->set_type(UPB_TYPE(MESSAGE)); - } - - if (upb_f->IsSubmessage()) { - const Message* prototype = upb::GetPrototypeForField(*m, proto2_f); - upb_f->set_subtype_name(prototype->GetDescriptor()->full_name()); - upb_f->prototype = prototype; - } - - upb_f->set_accessor(GetForCrep(f->crep)); - upb_f->set_hasbit(GetHasbit(proto2_f, r)); - upb_f->set_offset(GetOffset(proto2_f, r)); - return true; - } - - private: - static int16_t GetHasbit(const FieldDescriptor* f, - const _pi::Proto2Reflection* r) { - if (f->is_repeated()) { - // proto1 does not store hasbits for repeated fields. - return -1; - } else { - return (r->layout_->has_bit_offset * 8) + r->GetFieldLayout(f)->has_index; - } - } - - static uint16_t GetOffset(const FieldDescriptor* f, - const _pi::Proto2Reflection* r) { - return r->GetFieldLayout(f)->offset; - } - - static AccessorVTable *GetForCrep(int crep) { -#define PRIMITIVE(name, type_name) \ - case _pi::CREP_REQUIRED_ ## name: \ - case _pi::CREP_OPTIONAL_ ## name: \ - case _pi::CREP_REPEATED_ ## name: return Get(); - - switch (crep) { - PRIMITIVE(DOUBLE, double); - PRIMITIVE(FLOAT, float); - PRIMITIVE(INT64, int64_t); - PRIMITIVE(UINT64, uint64_t); - PRIMITIVE(INT32, int32_t); - PRIMITIVE(FIXED64, uint64_t); - PRIMITIVE(FIXED32, uint32_t); - PRIMITIVE(BOOL, bool); - case _pi::CREP_REQUIRED_STRING: - case _pi::CREP_OPTIONAL_STRING: - case _pi::CREP_REPEATED_STRING: return GetForString(); - case _pi::CREP_OPTIONAL_OUTOFLINE_STRING: return GetForOutOfLineString(); - case _pi::CREP_REQUIRED_CORD: - case _pi::CREP_OPTIONAL_CORD: - case _pi::CREP_REPEATED_CORD: return GetForCord(); - case _pi::CREP_REQUIRED_GROUP: - case _pi::CREP_REQUIRED_FOREIGN: - case _pi::CREP_REQUIRED_FOREIGN_PROTO2: return GetForRequiredMessage(); - case _pi::CREP_OPTIONAL_GROUP: - case _pi::CREP_REPEATED_GROUP: - case _pi::CREP_OPTIONAL_FOREIGN: - case _pi::CREP_REPEATED_FOREIGN: - case _pi::CREP_OPTIONAL_FOREIGN_PROTO2: - case _pi::CREP_REPEATED_FOREIGN_PROTO2: return GetForMessage(); - case _pi::CREP_OPTIONAL_FOREIGN_WEAK: return GetForWeakMessage(); - default: assert(false); return NULL; - } -#undef PRIMITIVE - } - - // PushOffset handler (used for StartSequence and others) /////////////////// - - // We can find a RepeatedField* or a RepeatedPtrField* at f->offset(). - static SubFlow PushOffset(void *m, Value fval) { - const FieldDef *f = GetValue(fval); - return UPB_CONTINUE_WITH(GetFieldPointer(m, f)); - } - - // Primitive Value (numeric, enum, bool) ///////////////////////////////////// - - template static AccessorVTable *Get() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - GetValueHandler(), - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &Append, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - template - static Flow Append(void *_r, Value fval, Value val) { - (void)fval; - // Proto1's ProtoArray class derives from RepeatedField. - RepeatedField* r = static_cast*>(_r); - r->Add(GetValue(val)); - return UPB_CONTINUE; - } - - // String //////////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForString() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - &SetString, - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &AppendString, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static Flow SetString(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - string *str = static_cast(GetFieldPointer(m, f)); - GetValue(val)->AssignToString(str); - return UPB_CONTINUE; - } - - static Flow AppendString(void *_r, Value fval, Value val) { - (void)fval; - RepeatedPtrField* r = static_cast*>(_r); - GetValue(val)->AssignToString(r->Add()); - return UPB_CONTINUE; - } - - // Out-of-line string //////////////////////////////////////////////////////// - - static AccessorVTable *GetForOutOfLineString() { - static upb_accessor_vtbl vtbl = { - NULL, &SetOutOfLineString, - // This type is only used for non-repeated string fields. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static Flow SetOutOfLineString(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - string **str = static_cast(GetFieldPointer(m, f)); - if (*str == &::ProtocolMessage::___empty_internal_proto_string_) - *str = new string(); - GetValue(val)->AssignToString(*str); - return UPB_CONTINUE; - } - - // Cord ////////////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForCord() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - &SetCord, - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &AppendCord, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static Flow SetCord(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - Cord* field = static_cast(GetFieldPointer(m, f)); - AssignToCord(GetValue(val), field); - return UPB_CONTINUE; - } - - static Flow AppendCord(void *_r, Value fval, Value val) { - RepeatedField* r = static_cast*>(_r); - AssignToCord(GetValue(val), r->Add()); - return UPB_CONTINUE; - } - - // SubMessage //////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForRequiredMessage() { - static upb_accessor_vtbl vtbl = { - &PushOffset, // StartSubMessage handler - NULL, // Value handler - &PushOffset, // StartSequence handler - &StartRepeatedSubMessage, - NULL, // Repeated value handler - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static AccessorVTable *GetForWeakMessage() { - static upb_accessor_vtbl vtbl = { - &StartWeakSubMessage, // StartSubMessage handler - NULL, // Value handler - &PushOffset, // StartSequence handler - &StartRepeatedSubMessage, - NULL, // Repeated value handler - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static AccessorVTable *GetForMessage() { - static upb_accessor_vtbl vtbl = { - &StartSubMessage, - NULL, // Value handler - &PushOffset, // StartSequence handler - &StartRepeatedSubMessage, - NULL, // Repeated value handler - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static SubFlow StartSubMessage(void *m, Value fval) { - const FieldDef* f = GetValue(fval); - Message **subm = static_cast(GetFieldPointer(m, f)); - if (*subm == f->prototype) *subm = (*subm)->New(); - return UPB_CONTINUE_WITH(*subm); - } - - static SubFlow StartWeakSubMessage(void *m, Value fval) { - const FieldDef* f = GetValue(fval); - Message **subm = static_cast(GetFieldPointer(m, f)); - if (*subm == NULL) { - const Message* prototype = static_cast(f->prototype); - *subm = prototype->New(); - } - return UPB_CONTINUE_WITH(*subm); - } - - class RepeatedMessageTypeHandler { - public: - typedef void Type; - // AddAllocated() calls this, but only if other objects are sitting - // around waiting for reuse, which we will not do. - static void Delete(Type* t) { - (void)t; - assert(false); - } - }; - - // Closure is a RepeatedPtrField*, but we access it through - // its base class RepeatedPtrFieldBase*. - static SubFlow StartRepeatedSubMessage(void* _r, Value fval) { - const FieldDef* f = GetValue(fval); - RepeatedPtrFieldBase *r = static_cast(_r); - void *submsg = r->AddFromCleared(); - if (!submsg) { - const Message* prototype = static_cast(f->prototype); - submsg = prototype->New(); - r->AddAllocated(submsg); - } - return UPB_CONTINUE_WITH(submsg); - } -}; - -#endif - -} // namespace proto2_bridge_{google3,opensource} - -static const Message* GetPrototypeForMessage(const Message& m) { - const Message* ret = NULL; - MessageFactory* factory = FieldAccessor::GetMessageFactory(m); - if (factory) { - // proto2 generated message or DynamicMessage. - ret = factory->GetPrototype(m.GetDescriptor()); - assert(ret); - } else { - // Proto1 message; since proto1 has no dynamic message, it must be - // from the generated factory. - ret = MessageFactory::generated_factory()->GetPrototype(m.GetDescriptor()); - assert(ret); // If NULL, then wasn't a proto1 message, can't handle it. - } - assert(ret->GetReflection() == m.GetReflection()); - return ret; -} - -static const Message* GetPrototypeForField(const Message& m, - const FieldDescriptor* f) { -#ifdef UPB_GOOGLE3 - if (f->type() == FieldDescriptor::TYPE_BYTES) { - // Proto1 weak field: the proto2 descriptor says their type is BYTES. - const _pi::Proto2Reflection* r = - dynamic_cast(m.GetReflection()); - assert(r); - const _pi::Field* field = r->GetFieldLayout(f); - assert(field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK); - return GetPrototypeForMessage( - *static_cast(field->weak_layout()->default_instance)); - } else if (dynamic_cast(m.GetReflection())) { - // Proto1 message; since proto1 has no dynamic message, it must be from - // the generated factory. - const Message* ret = - MessageFactory::generated_factory()->GetPrototype(f->message_type()); - assert(ret); - return ret; - } -#endif - assert(f->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); - // We assume that all submessages (and extensions) will be constructed using - // the same MessageFactory as this message. This doesn't cover the case of - // CodedInputStream::SetExtensionRegistry(). - MessageFactory* factory = FieldAccessor::GetMessageFactory(m); - assert(factory); // If neither proto1 nor proto2 we can't handle it. - const Message* ret = factory->GetPrototype(f->message_type()); - assert(ret); - return ret; -} - -namespace proto2_bridge { - -upb::FieldDef* AddFieldDef(const FieldDescriptor* f, upb::MessageDef* md) { - upb::FieldDef* upb_f = upb::FieldDef::New(&upb_f); - upb_f->set_number(f->number()); - upb_f->set_name(f->name()); - upb_f->set_label(static_cast(f->label())); - upb_f->set_type(static_cast(f->type())); - - if (!FieldAccessor::TrySet(f, md, upb_f) -#ifdef UPB_GOOGLE3 - && !proto2_bridge_google3::Proto1FieldAccessor::TrySet(f, md, upb_f) -#endif - ) { - // Unsupported reflection class. - assert(false); - } - - if (upb_f->type() == UPB_TYPE(ENUM)) { - // We set the enum default symbolically. - upb_f->set_default(f->default_value_enum()->name()); - upb_f->set_subtype_name(f->enum_type()->full_name()); - } else { - // Set field default for primitive types. Need to switch on the upb type - // rather than the proto2 type, because upb_f->type() may have been changed - // from BYTES to MESSAGE for a weak field. - switch (upb_types[upb_f->type()].inmemory_type) { - case UPB_CTYPE_INT32: - upb_f->set_default(MakeValue(f->default_value_int32())); - break; - case UPB_CTYPE_INT64: - upb_f->set_default( - MakeValue(static_cast(f->default_value_int64()))); - break; - case UPB_CTYPE_UINT32: - upb_f->set_default(MakeValue(f->default_value_uint32())); - break; - case UPB_CTYPE_UINT64: - upb_f->set_default( - MakeValue(static_cast(f->default_value_uint64()))); - break; - case UPB_CTYPE_DOUBLE: - upb_f->set_default(MakeValue(f->default_value_double())); - break; - case UPB_CTYPE_FLOAT: - upb_f->set_default(MakeValue(f->default_value_float())); - break; - case UPB_CTYPE_BOOL: - upb_f->set_default(MakeValue(f->default_value_bool())); - break; - case UPB_CTYPE_BYTEREGION: - upb_f->set_default(f->default_value_string()); - break; - } - } - return md->AddField(upb_f, &upb_f) ? upb_f : NULL; -} - -upb::MessageDef *NewEmptyMessageDef(const Message& m, void *owner) { - upb::MessageDef *md = upb::MessageDef::New(owner); - md->set_full_name(m.GetDescriptor()->full_name()); - md->prototype = GetPrototypeForMessage(m); - return md; -} - -upb::EnumDef* NewEnumDef(const EnumDescriptor* desc, void *owner) { - upb::EnumDef* e = upb::EnumDef::New(owner); - e->set_full_name(desc->full_name()); - for (int i = 0; i < desc->value_count(); i++) { - const EnumValueDescriptor* val = desc->value(i); - bool success = e->AddValue(val->name(), val->number()); - assert(success); - (void)success; - } - return e; -} - -void AddAllFields(upb::MessageDef* md) { - const Descriptor* d = - static_cast(md->prototype)->GetDescriptor(); - for (int i = 0; i < d->field_count(); i++) { -#ifdef UPB_GOOGLE3 - // Skip lazy fields for now since we can't properly handle them. - if (d->field(i)->options().lazy()) continue; -#endif - // Extensions not supported yet. - if (d->field(i)->is_extension()) continue; - AddFieldDef(d->field(i), md); - } -} - -upb::MessageDef *NewFullMessageDef(const Message& m, void *owner) { - upb::MessageDef* md = NewEmptyMessageDef(m, owner); - AddAllFields(md); - // TODO(haberman): add unknown field handler and extensions. - return md; -} - -typedef std::map SymbolMap; - -static upb::MessageDef* NewFinalMessageDefHelper(const Message& m, void *owner, - SymbolMap* symbols) { - upb::MessageDef* md = NewFullMessageDef(m, owner); - // Must do this before processing submessages to prevent infinite recursion. - (*symbols)[std::string(md->full_name())] = md->AsDef(); - - for (upb::MessageDef::Iterator i(md); !i.Done(); i.Next()) { - upb::FieldDef* f = i.field(); - if (!f->HasSubDef()) continue; - SymbolMap::iterator iter = symbols->find(f->subtype_name()); - upb::Def* subdef; - if (iter != symbols->end()) { - subdef = iter->second; - } else { - const FieldDescriptor* proto2_f = - m.GetDescriptor()->FindFieldByNumber(f->number()); - if (f->type() == UPB_TYPE(ENUM)) { - subdef = NewEnumDef(proto2_f->enum_type(), owner)->AsDef(); - (*symbols)[std::string(subdef->full_name())] = subdef; - } else { - assert(f->IsSubmessage()); - const Message* prototype = GetPrototypeForField(m, proto2_f); - subdef = NewFinalMessageDefHelper(*prototype, owner, symbols)->AsDef(); - } - } - f->set_subdef(subdef); - } - return md; -} - -const upb::MessageDef* NewFinalMessageDef(const Message& m, void *owner) { - SymbolMap symbols; - upb::MessageDef* ret = NewFinalMessageDefHelper(m, owner, &symbols); - - // Finalize defs. - std::vector defs; - SymbolMap::iterator iter; - for (iter = symbols.begin(); iter != symbols.end(); ++iter) { - defs.push_back(iter->second); - } - Status status; - bool success = Def::Finalize(defs, &status); - assert(success); - (void)success; - - // Unref all defs except the top-level one that we are returning. - for (int i = 0; i < static_cast(defs.size()); i++) { - if (defs[i] != ret->AsDef()) defs[i]->Unref(owner); - } - - return ret; -} - -} // namespace proto2_bridge -} // namespace upb diff --git a/bindings/cpp/upb/proto2_bridge.hpp b/bindings/cpp/upb/proto2_bridge.hpp deleted file mode 100644 index ace08ce..0000000 --- a/bindings/cpp/upb/proto2_bridge.hpp +++ /dev/null @@ -1,170 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. -// Author: Josh Haberman -// -// A bridge between upb and proto2, allows populating proto2 generated -// classes using upb's parser, translating between descriptors and defs, etc. -// -// This is designed to be able to be compiled against either the open-source -// version of protocol buffers or the Google-internal proto2. The two are -// the same in most ways, but live in different namespaces (proto2 vs -// google::protobuf) and have a few other more minor differences. -// -// The bridge gives you a lot of control over which fields will be written to -// the message (fields that are not written will just be skipped), and whether -// unknown fields are written to the UnknownFieldSet. This can save a lot of -// work if the client only cares about some subset of the fields. -// -// Example usage: -// -// // Build a def that will have all fields and parse just like proto2 would. -// const upb::MessageDef* md = upb::proto2_bridge::NewMessageDef(&MyProto()); -// -// // JIT the parser; should only be done once ahead-of-time. -// upb::Handlers* handlers = upb::NewHandlersForMessage(md); -// upb::DecoderPlan* plan = upb::DecoderPlan::New(handlers); -// handlers->Unref(); -// -// // The actual parsing. -// MyProto proto; -// upb::Decoder decoder; -// upb::StringSource source(buf, len); -// decoder.ResetPlan(plan, 0); -// decoder.ResetInput(source.AllBytes(), &proto); -// CHECK(decoder.Decode() == UPB_OK) << decoder.status(); -// -// To parse only one field and skip all others: -// -// const upb::MessageDef* md = -// upb::proto2_bridge::NewEmptyMessageDef(MyProto().GetPrototype()); -// upb::proto2_bridge::AddFieldDef( -// MyProto::descriptor()->FindFieldByName("my_field"), md); -// upb::Finalize(md); -// -// // Now continue with "JIT the parser" from above. -// -// Note that there is currently no support for -// CodedInputStream::SetExtensionRegistry(), which allows specifying a separate -// DescriptorPool and MessageFactory for extensions. Since this is a property -// of the input in proto2, it's difficult to build a plan ahead-of-time that -// can properly support this. If it's an important use case, the caller should -// probably build a upb plan explicitly. - -#ifndef UPB_PROTO2_BRIDGE -#define UPB_PROTO2_BRIDGE - -#include - -namespace google { -namespace protobuf { -class Descriptor; -class EnumDescriptor; -class FieldDescriptor; -class FileDescriptor; -class Message; -} // namespace google -} // namespace protobuf - -namespace proto2 { -class Descriptor; -class EnumDescriptor; -class FieldDescriptor; -class FileDescriptor; -class Message; -} // namespace proto2 - - -namespace upb { - -class Def; -class FieldDef; -class MessageDef; - -namespace proto2_bridge { - -// Unfinalized defs //////////////////////////////////////////////////////////// - -// Creating of UNFINALIZED defs. All of these functions return defs that are -// still mutable and have not been finalized. They must be finalized before -// using them to parse anything. This is useful if you want more control over -// the process of constructing defs, eg. to add the specific set of fields you -// care about. - -// Creates a new upb::MessageDef that corresponds to the type in the given -// prototype message. The MessageDef will not have any fields added to it. -upb::MessageDef *NewEmptyMessageDef(const proto2::Message& m, void *owner); -upb::MessageDef *NewEmptyMessageDef(const google::protobuf::Message& desc, - void *owner); - -// Adds a new upb::FieldDef to the given MessageDef corresponding to the given -// FieldDescriptor. The FieldDef will be given an accessor and offset so that -// it can be used to read and write data into the proto2::Message classes. -// The given MessageDef must have been constructed with NewEmptyDefForMessage() -// and f->containing_type() must correspond to the message that was used. -// -// Any submessage, group, or enum fields will be given symbolic references to -// the subtype, which must be resolved before the MessageDef can be finalized. -// -// On success, returns the FieldDef that was added (caller does not own a ref). -// If an existing field had the same name or number, returns NULL. -upb::FieldDef* AddFieldDef(const proto2::FieldDescriptor* f, - upb::MessageDef* md); -upb::FieldDef* AddFieldDef(const google::protobuf::FieldDescriptor* f, - upb::MessageDef* md); - -// Given a MessageDef that was constructed with NewEmptyDefForMessage(), adds -// FieldDefs for all fields defined in the original message, but not for any -// extensions or unknown fields. The given MessageDef must not have any fields -// that have the same name or number as any of the fields we are adding (the -// easiest way to guarantee this is to start with an empty MessageDef). -// -// Returns true on success or false if any of the fields could not be added. -void AddAllFields(upb::MessageDef* md); - -// TODO(haberman): Add: -// // Adds a handler that will store unknown fields in the UnknownFieldSet. -// void AddUnknownFieldHandler(upb::MessageDef* md); - -// Returns a new upb::MessageDef that contains handlers for all fields, unknown -// fields, and any extensions in the descriptor's pool. The resulting -// def/handlers should be equivalent to the generated code constructed by the -// protobuf compiler (or the code in DynamicMessage) for the given type. -// The subdefs for message/enum fields (if any) will be referenced symbolically, -// and will need to be resolved before being finalized. -// -// TODO(haberman): Add missing support (LazyField, MessageSet, and extensions). -// -// TODO(haberman): possibly add a similar function that lets you supply a -// separate DescriptorPool and MessageFactory for extensions, to support -// proto2's io::CodedInputStream::SetExtensionRegistry(). -upb::MessageDef* NewFullMessageDef(const proto2::Message& m, void *owner); -upb::MessageDef* NewFullMessageDef(const google::protobuf::Message& m, - void *owner); - -// Returns a new upb::EnumDef that corresponds to the given EnumDescriptor. -// Caller owns a ref on the returned EnumDef. -upb::EnumDef* NewEnumDef(const proto2::EnumDescriptor* desc, void *owner); -upb::EnumDef* NewEnumDef(const google::protobuf::EnumDescriptor* desc, - void *owner); - -// Finalized defs ////////////////////////////////////////////////////////////// - -// These functions return FINALIZED defs, meaning that they are immutable and -// ready for use. Since they are immutable you cannot make any further changes -// to eg. the set of fields, but these functions are more convenient if you -// simply want to parse a message exactly how the built-in proto2 parser would. - -// Creates a returns a finalized MessageDef for the give message and its entire -// type tree that will include all fields and unknown handlers (ie. it will -// parse just like proto2 would). -const upb::MessageDef* NewFinalMessageDef(const proto2::Message& m, - void *owner); -const upb::MessageDef* NewFinalMessageDef(const google::protobuf::Message& m, - void *owner); - -} // namespace proto2_bridge -} // namespace upb - -#endif diff --git a/bindings/cpp/upb/upb.hpp b/bindings/cpp/upb/upb.hpp deleted file mode 100644 index 48c2708..0000000 --- a/bindings/cpp/upb/upb.hpp +++ /dev/null @@ -1,81 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011 Google Inc. See LICENSE for details. -// Author: Josh Haberman - -#ifndef UPB_HPP -#define UPB_HPP - -#include "upb/upb.h" -#include - -#if defined(__GXX_EXPERIMENTAL_CXX0X__) && !defined(UPB_NO_CXX11) -#define UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(class_name) \ - class_name() = delete; \ - ~class_name() = delete; -#else -#define UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(class_name) \ - class_name(); \ - ~class_name(); -#endif - -namespace upb { - -typedef upb_success_t Success; - -class Status : public upb_status { - public: - Status() { upb_status_init(this); } - ~Status() { upb_status_uninit(this); } - - bool ok() const { return upb_ok(this); } - bool eof() const { return upb_eof(this); } - - const char *GetString() const { return upb_status_getstr(this); } - void SetEof() { upb_status_seteof(this); } - void SetErrorLiteral(const char* msg) { - upb_status_seterrliteral(this, msg); - } - - void Clear() { upb_status_clear(this); } -}; - -typedef upb_value Value; - -template T GetValue(Value v); -template Value MakeValue(T v); - -#define UPB_VALUE_ACCESSORS(type, ctype) \ - template <> inline ctype GetValue(Value v) { \ - return upb_value_get ## type(v); \ - } \ - template <> inline Value MakeValue(ctype v) { \ - return upb_value_ ## type(v); \ - } - -UPB_VALUE_ACCESSORS(double, double); -UPB_VALUE_ACCESSORS(float, float); -UPB_VALUE_ACCESSORS(int32, int32_t); -UPB_VALUE_ACCESSORS(int64, int64_t); -UPB_VALUE_ACCESSORS(uint32, uint32_t); -UPB_VALUE_ACCESSORS(uint64, uint64_t); -UPB_VALUE_ACCESSORS(bool, bool); - -#undef UPB_VALUE_ACCESSORS - -template inline T* GetPtrValue(Value v) { - return static_cast(upb_value_getptr(v)); -} -template inline Value MakePtrValue(T* v) { - return upb_value_ptr(static_cast(v)); -} - -INLINE std::ostream& operator<<(std::ostream& out, const Status& status) { - out << status.GetString(); - return out; -} - -} // namespace upb - -#endif diff --git a/bindings/linux/Makefile b/bindings/linux/Makefile index e98aa3c..1736b61 100644 --- a/bindings/linux/Makefile +++ b/bindings/linux/Makefile @@ -1,7 +1,6 @@ obj-m = upb.o upb-objs = \ - setjmp.o \ ../../upb/upb.o \ ../../upb/bytestream.o \ ../../upb/def.o \ @@ -9,9 +8,6 @@ upb-objs = \ ../../upb/table.o \ ../../upb/refcount.o \ ../../upb/msg.o \ - ../../upb/pb/decoder.o \ - ../../upb/pb/textprinter.o \ - ../../upb/pb/varint.o \ KVERSION = $(shell uname -r) diff --git a/bindings/linux/ctype.h b/bindings/linux/ctype.h deleted file mode 100644 index b6cbda5..0000000 --- a/bindings/linux/ctype.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2012 Google Inc. See LICENSE for details. - * Author: Josh Haberman - */ - -#include diff --git a/bindings/linux/inttypes.h b/bindings/linux/inttypes.h deleted file mode 100644 index e7a6e42..0000000 --- a/bindings/linux/inttypes.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2012 Google Inc. See LICENSE for details. - * Author: Josh Haberman - */ - -#ifndef PRId64 -#define PRId64 "ld" -#endif - -#ifndef PRIu64 -#define PRIu64 "lu" -#endif - -#ifndef PRId32 -#define PRId32 "d" -#endif - -#ifndef PRIu32 -#define PRIu32 "u" -#endif diff --git a/bindings/linux/setjmp.S b/bindings/linux/setjmp.S deleted file mode 100644 index 5eea4be..0000000 --- a/bindings/linux/setjmp.S +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2003 Peter Wemm. - * Copyright (c) 1993 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -.globl _setjmp, _longjmp - -_setjmp: - movq %rbx,0(%rdi) /* save rbx */ - movq %rsp,8(%rdi) /* save rsp */ - movq %rbp,16(%rdi) /* save rbp */ - movq %r12,24(%rdi) /* save r12 */ - movq %r13,32(%rdi) /* save r13 */ - movq %r14,40(%rdi) /* save r14 */ - movq %r15,48(%rdi) /* save r15 */ - movq 0(%rsp),%rdx /* get rta */ - movq %rdx,56(%rdi) /* save rip */ - xorl %eax,%eax /* return(0); */ - ret - -_longjmp: - movq 0(%rdi),%rbx /* restore rbx */ - movq 8(%rdi),%rsp /* restore rsp */ - movq 16(%rdi),%rbp /* restore rbp */ - movq 24(%rdi),%r12 /* restore r12 */ - movq 32(%rdi),%r13 /* restore r13 */ - movq 40(%rdi),%r14 /* restore r14 */ - movq 48(%rdi),%r15 /* restore r15 */ - movq 56(%rdi),%rdx /* get rta */ - movq %rdx,0(%rsp) /* put in return frame */ - xorl %eax,%eax /* return(1); */ - incl %eax - ret diff --git a/bindings/linux/setjmp.h b/bindings/linux/setjmp.h deleted file mode 100644 index c4716e6..0000000 --- a/bindings/linux/setjmp.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2012 Google Inc. See LICENSE for details. - * Author: Josh Haberman - */ - -// Linux doesn't provide setjmp/longjmp, boo. - -typedef void *jmp_buf[8]; - -extern int _setjmp(jmp_buf env); -__attribute__((__noreturn__)) extern void _longjmp(jmp_buf env, int val); diff --git a/bindings/linux/string.h b/bindings/linux/string.h index 69de3fa..30ebf8a 100644 --- a/bindings/linux/string.h +++ b/bindings/linux/string.h @@ -9,18 +9,5 @@ #define UPB_LINUX_STRING_H_ #include -#include -#include "upb/upb.h" // For INLINE. - -INLINE char *strdup(const char *s) { - size_t len = strlen(s); - char *ret = malloc(len + 1); - if (ret == NULL) return NULL; - // Be particularly defensive and guard against buffer overflow if there - // is a concurrent mutator. - strncpy(ret, s, len); - ret[len] = '\0'; - return ret; -} #endif /* UPB_DEF_H_ */ diff --git a/bindings/lua/LICENSE b/bindings/lua/LICENSE new file mode 100644 index 0000000..fb720fe --- /dev/null +++ b/bindings/lua/LICENSE @@ -0,0 +1,32 @@ + +Lunit License +------------- + +Lunit is written by Michael Roth and is licensed +under the terms of the MIT license reproduced below. + +======================================================================== + +Copyright (c) 2004-2010 Michael Roth + +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/bindings/lua/lunitx/atexit.lua b/bindings/lua/lunitx/atexit.lua new file mode 100644 index 0000000..c3cdddc --- /dev/null +++ b/bindings/lua/lunitx/atexit.lua @@ -0,0 +1,32 @@ + +local actions = {} + +local atexit + +if _VERSION >= 'Lua 5.2' then + + atexit = function (fn) + actions[#actions+1] = setmetatable({}, { __gc = fn }) + end + +else + + local newproxy = newproxy + local debug = debug + local assert = assert + local setmetatable = setmetatable + + local function gc(fn) + local p = assert(newproxy()) + assert(debug.setmetatable(p, { __gc = fn })) + return p + end + + atexit = function (fn) + actions[#actions+1] = gc(fn) + end + +end + +return atexit + diff --git a/bindings/lua/lunitx/lunit.lua b/bindings/lua/lunitx/lunit.lua new file mode 100644 index 0000000..8fa87de --- /dev/null +++ b/bindings/lua/lunitx/lunit.lua @@ -0,0 +1,725 @@ +--[[-------------------------------------------------------------------------- + + This file is part of lunit 0.5. + + For Details about lunit look at: http://www.mroth.net/lunit/ + + Author: Michael Roth + + Copyright (c) 2004, 2006-2010 Michael Roth + + 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. + +--]]-------------------------------------------------------------------------- + + +local orig_assert = assert + +local pairs = pairs +local ipairs = ipairs +local next = next +local type = type +local error = error +local tostring = tostring +local setmetatable = setmetatable +local pcall = pcall +local xpcall = xpcall +local require = require +local loadfile = loadfile + +local string_sub = string.sub +local string_gsub = string.gsub +local string_format = string.format +local string_lower = string.lower +local string_find = string.find + +local table_concat = table.concat + +local debug_getinfo = debug.getinfo + +local _G = _G + +local lunit + +if _VERSION >= 'Lua 5.2' then + + lunit = {} + _ENV = lunit + +else + + module("lunit") + lunit = _M + +end + + +local __failure__ = {} -- Type tag for failed assertions + +local typenames = { "nil", "boolean", "number", "string", "table", "function", "thread", "userdata" } + + +local traceback_hide -- Traceback function which hides lunit internals +local mypcall -- Protected call to a function with own traceback +do + local _tb_hide = setmetatable( {}, {__mode="k"} ) + + function traceback_hide(func) + _tb_hide[func] = true + end + + local function my_traceback(errobj) + if is_table(errobj) and errobj.type == __failure__ then + local info = debug_getinfo(5, "Sl") -- FIXME: Hardcoded integers are bad... + errobj.where = string_format( "%s:%d", info.short_src, info.currentline) + else + errobj = { msg = tostring(errobj) } + errobj.tb = {} + local i = 2 + while true do + local info = debug_getinfo(i, "Snlf") + if not is_table(info) then + break + end + if not _tb_hide[info.func] then + local line = {} -- Ripped from ldblib.c... + line[#line+1] = string_format("%s:", info.short_src) + if info.currentline > 0 then + line[#line+1] = string_format("%d:", info.currentline) + end + if info.namewhat ~= "" then + line[#line+1] = string_format(" in function '%s'", info.name) + else + if info.what == "main" then + line[#line+1] = " in main chunk" + elseif info.what == "C" or info.what == "tail" then + line[#line+1] = " ?" + else + line[#line+1] = string_format(" in function <%s:%d>", info.short_src, info.linedefined) + end + end + errobj.tb[#errobj.tb+1] = table_concat(line) + end + i = i + 1 + end + end + return errobj + end + + function mypcall(func) + orig_assert( is_function(func) ) + local ok, errobj = xpcall(func, my_traceback) + if not ok then + return errobj + end + end + traceback_hide(mypcall) +end + + +-- Type check functions + +for _, typename in ipairs(typenames) do + lunit["is_"..typename] = function(x) + return type(x) == typename + end +end + +local is_nil = is_nil +local is_boolean = is_boolean +local is_number = is_number +local is_string = is_string +local is_table = is_table +local is_function = is_function +local is_thread = is_thread +local is_userdata = is_userdata + + +local function failure(name, usermsg, defaultmsg, ...) + local errobj = { + type = __failure__, + name = name, + msg = string_format(defaultmsg,...), + usermsg = usermsg + } + error(errobj, 0) +end +traceback_hide( failure ) + + +local function format_arg(arg) + local argtype = type(arg) + if argtype == "string" then + return "'"..arg.."'" + elseif argtype == "number" or argtype == "boolean" or argtype == "nil" then + return tostring(arg) + else + return "["..tostring(arg).."]" + end +end + + +local function selected(map, name) + if not map then + return true + end + + local m = {} + for k,v in pairs(map) do + m[k] = lunitpat2luapat(v) + end + return in_patternmap(m, name) +end + + +function fail(msg) + stats.assertions = stats.assertions + 1 + failure( "fail", msg, "failure" ) +end +traceback_hide( fail ) + + +function assert(assertion, msg) + stats.assertions = stats.assertions + 1 + if not assertion then + failure( "assert", msg, "assertion failed" ) + end + return assertion +end +traceback_hide( assert ) + + +function assert_true(actual, msg) + stats.assertions = stats.assertions + 1 + if actual ~= true then + failure( "assert_true", msg, "true expected but was %s", format_arg(actual) ) + end + return actual +end +traceback_hide( assert_true ) + + +function assert_false(actual, msg) + stats.assertions = stats.assertions + 1 + if actual ~= false then + failure( "assert_false", msg, "false expected but was %s", format_arg(actual) ) + end + return actual +end +traceback_hide( assert_false ) + + +function assert_equal(expected, actual, msg) + stats.assertions = stats.assertions + 1 + if expected ~= actual then + failure( "assert_equal", msg, "expected %s but was %s", format_arg(expected), format_arg(actual) ) + end + return actual +end +traceback_hide( assert_equal ) + + +function assert_not_equal(unexpected, actual, msg) + stats.assertions = stats.assertions + 1 + if unexpected == actual then + failure( "assert_not_equal", msg, "%s not expected but was one", format_arg(unexpected) ) + end + return actual +end +traceback_hide( assert_not_equal ) + + +function assert_match(pattern, actual, msg) + stats.assertions = stats.assertions + 1 + if type(pattern) ~= "string" then + failure( "assert_match", msg, "expected a string as pattern but was %s", format_arg(pattern) ) + end + if type(actual) ~= "string" then + failure( "assert_match", msg, "expected a string to match pattern '%s' but was a %s", pattern, format_arg(actual) ) + end + if not string_find(actual, pattern) then + failure( "assert_match", msg, "expected '%s' to match pattern '%s' but doesn't", actual, pattern ) + end + return actual +end +traceback_hide( assert_match ) + + +function assert_not_match(pattern, actual, msg) + stats.assertions = stats.assertions + 1 + if type(pattern) ~= "string" then + failure( "assert_not_match", msg, "expected a string as pattern but was %s", format_arg(pattern) ) + end + if type(actual) ~= "string" then + failure( "assert_not_match", msg, "expected a string to not match pattern '%s' but was %s", pattern, format_arg(actual) ) + end + if string_find(actual, pattern) then + failure( "assert_not_match", msg, "expected '%s' to not match pattern '%s' but it does", actual, pattern ) + end + return actual +end +traceback_hide( assert_not_match ) + + +function assert_error(msg, func) + stats.assertions = stats.assertions + 1 + if func == nil then + func, msg = msg, nil + end + if type(func) ~= "function" then + failure( "assert_error", msg, "expected a function as last argument but was %s", format_arg(func) ) + end + local ok, errmsg = pcall(func) + if ok then + failure( "assert_error", msg, "error expected but no error occurred" ) + end +end +traceback_hide( assert_error ) + + +function assert_error_match(msg, pattern, func) + stats.assertions = stats.assertions + 1 + if func == nil then + msg, pattern, func = nil, msg, pattern + end + if type(pattern) ~= "string" then + failure( "assert_error_match", msg, "expected the pattern as a string but was %s", format_arg(pattern) ) + end + if type(func) ~= "function" then + failure( "assert_error_match", msg, "expected a function as last argument but was %s", format_arg(func) ) + end + local ok, errmsg = pcall(func) + if ok then + failure( "assert_error_match", msg, "error expected but no error occurred" ) + end + if type(errmsg) ~= "string" then + failure( "assert_error_match", msg, "error as string expected but was %s", format_arg(errmsg) ) + end + if not string_find(errmsg, pattern) then + failure( "assert_error_match", msg, "expected error '%s' to match pattern '%s' but doesn't", errmsg, pattern ) + end +end +traceback_hide( assert_error_match ) + + +function assert_pass(msg, func) + stats.assertions = stats.assertions + 1 + if func == nil then + func, msg = msg, nil + end + if type(func) ~= "function" then + failure( "assert_pass", msg, "expected a function as last argument but was %s", format_arg(func) ) + end + local ok, errmsg = pcall(func) + if not ok then + failure( "assert_pass", msg, "no error expected but error was: '%s'", errmsg ) + end +end +traceback_hide( assert_pass ) + + +-- lunit.assert_typename functions + +for _, typename in ipairs(typenames) do + local assert_typename = "assert_"..typename + lunit[assert_typename] = function(actual, msg) + stats.assertions = stats.assertions + 1 + if type(actual) ~= typename then + failure( assert_typename, msg, "%s expected but was %s", typename, format_arg(actual) ) + end + return actual + end + traceback_hide( lunit[assert_typename] ) +end + + +-- lunit.assert_not_typename functions + +for _, typename in ipairs(typenames) do + local assert_not_typename = "assert_not_"..typename + lunit[assert_not_typename] = function(actual, msg) + stats.assertions = stats.assertions + 1 + if type(actual) == typename then + failure( assert_not_typename, msg, typename.." not expected but was one" ) + end + end + traceback_hide( lunit[assert_not_typename] ) +end + + +function lunit.clearstats() + stats = { + assertions = 0; + passed = 0; + failed = 0; + errors = 0; + } +end + + +local report, reporterrobj +do + local testrunner + + function lunit.setrunner(newrunner) + if not ( is_table(newrunner) or is_nil(newrunner) ) then + return error("lunit.setrunner: Invalid argument", 0) + end + local oldrunner = testrunner + testrunner = newrunner + return oldrunner + end + + function lunit.loadrunner(name) + if not is_string(name) then + return error("lunit.loadrunner: Invalid argument", 0) + end + local ok, runner = pcall( require, name ) + if not ok then + return error("lunit.loadrunner: Can't load test runner: "..runner, 0) + end + return setrunner(runner) + end + + function lunit.getrunner() + return testrunner + end + + function report(event, ...) + local f = testrunner and testrunner[event] + if is_function(f) then + pcall(f, ...) + end + end + + function reporterrobj(context, tcname, testname, errobj) + local fullname = tcname .. "." .. testname + if context == "setup" then + fullname = fullname .. ":" .. setupname(tcname, testname) + elseif context == "teardown" then + fullname = fullname .. ":" .. teardownname(tcname, testname) + end + if errobj.type == __failure__ then + stats.failed = stats.failed + 1 + report("fail", fullname, errobj.where, errobj.msg, errobj.usermsg) + else + stats.errors = stats.errors + 1 + report("err", fullname, errobj.msg, errobj.tb) + end + end +end + + + +local function key_iter(t, k) + return (next(t,k)) +end + + +local testcase +do + -- Array with all registered testcases + local _testcases = {} + + -- Marks a module as a testcase. + -- Applied over a module from module("xyz", lunit.testcase). + function lunit.testcase(m) + orig_assert( is_table(m) ) + --orig_assert( m._M == m ) + orig_assert( is_string(m._NAME) ) + --orig_assert( is_string(m._PACKAGE) ) + + -- Register the module as a testcase + _testcases[m._NAME] = m + + -- Import lunit, fail, assert* and is_* function to the module/testcase + m.lunit = lunit + m.fail = lunit.fail + for funcname, func in pairs(lunit) do + if "assert" == string_sub(funcname, 1, 6) or "is_" == string_sub(funcname, 1, 3) then + m[funcname] = func + end + end + end + + function lunit.module(name,seeall) + local m = {} + if seeall == "seeall" then + setmetatable(m, { __index = _G }) + end + m._NAME = name + lunit.testcase(m) + return m + end + + -- Iterator (testcasename) over all Testcases + function lunit.testcases() + -- Make a copy of testcases to prevent confusing the iterator when + -- new testcase are defined + local _testcases2 = {} + for k,v in pairs(_testcases) do + _testcases2[k] = true + end + return key_iter, _testcases2, nil + end + + function testcase(tcname) + return _testcases[tcname] + end +end + + +do + -- Finds a function in a testcase case insensitive + local function findfuncname(tcname, name) + for key, value in pairs(testcase(tcname)) do + if is_string(key) and is_function(value) and string_lower(key) == name then + return key + end + end + end + + function lunit.setupname(tcname) + return findfuncname(tcname, "setup") + end + + function lunit.teardownname(tcname) + return findfuncname(tcname, "teardown") + end + + -- Iterator over all test names in a testcase. + -- Have to collect the names first in case one of the test + -- functions creates a new global and throws off the iteration. + function lunit.tests(tcname) + local testnames = {} + for key, value in pairs(testcase(tcname)) do + if is_string(key) and is_function(value) then + local lfn = string_lower(key) + if string_sub(lfn, 1, 4) == "test" or string_sub(lfn, -4) == "test" then + testnames[key] = true + end + end + end + return key_iter, testnames, nil + end +end + + + + +function lunit.runtest(tcname, testname) + orig_assert( is_string(tcname) ) + orig_assert( is_string(testname) ) + + if (not getrunner()) then + loadrunner("lunit.console") + end + + local function callit(context, func) + if func then + local err = mypcall(func) + if err then + reporterrobj(context, tcname, testname, err) + return false + end + end + return true + end + traceback_hide(callit) + + report("run", tcname, testname) + + local tc = testcase(tcname) + local setup = tc[setupname(tcname)] + local test = tc[testname] + local teardown = tc[teardownname(tcname)] + + local setup_ok = callit( "setup", setup ) + local test_ok = setup_ok and callit( "test", test ) + local teardown_ok = setup_ok and callit( "teardown", teardown ) + + if setup_ok and test_ok and teardown_ok then + stats.passed = stats.passed + 1 + report("pass", tcname, testname) + end +end +traceback_hide(runtest) + + + +function lunit.run(testpatterns) + clearstats() + report("begin") + for testcasename in lunit.testcases() do + -- Run tests in the testcases + for testname in lunit.tests(testcasename) do + if selected(testpatterns, testname) then + runtest(testcasename, testname) + end + end + end + report("done") + return stats +end +traceback_hide(run) + + +function lunit.loadonly() + clearstats() + report("begin") + report("done") + return stats +end + + + + + + + + + +local lunitpat2luapat +do + local conv = { + ["^"] = "%^", + ["$"] = "%$", + ["("] = "%(", + [")"] = "%)", + ["%"] = "%%", + ["."] = "%.", + ["["] = "%[", + ["]"] = "%]", + ["+"] = "%+", + ["-"] = "%-", + ["?"] = ".", + ["*"] = ".*" + } + function lunitpat2luapat(str) + --return "^" .. string.gsub(str, "%W", conv) .. "$" + -- Above was very annoying, if I want to run all the tests having to do with + -- RSS, I want to be able to do "-t rss" not "-t \*rss\*". + return string_gsub(str, "%W", conv) + end +end + + + +local function in_patternmap(map, name) + if map[name] == true then + return true + else + for _, pat in ipairs(map) do + if string_find(name, pat) then + return true + end + end + end + return false +end + + + + + + + + +-- Called from 'lunit' shell script. + +function main(argv) + argv = argv or {} + + -- FIXME: Error handling and error messages aren't nice. + + local function checkarg(optname, arg) + if not is_string(arg) then + return error("lunit.main: option "..optname..": argument missing.", 0) + end + end + + local function loadtestcase(filename) + if not is_string(filename) then + return error("lunit.main: invalid argument") + end + local chunk, err = loadfile(filename) + if err then + return error(err) + else + chunk() + end + end + + local testpatterns = nil + local doloadonly = false + + local i = 0 + while i < #argv do + i = i + 1 + local arg = argv[i] + if arg == "--loadonly" then + doloadonly = true + elseif arg == "--runner" or arg == "-r" then + local optname = arg; i = i + 1; arg = argv[i] + checkarg(optname, arg) + loadrunner(arg) + elseif arg == "--test" or arg == "-t" then + local optname = arg; i = i + 1; arg = argv[i] + checkarg(optname, arg) + testpatterns = testpatterns or {} + testpatterns[#testpatterns+1] = arg + elseif arg == "--help" or arg == "-h" then + print[[ +lunit 0.5 +Copyright (c) 2004-2009 Michael Roth +This program comes WITHOUT WARRANTY OF ANY KIND. + +Usage: lua test [OPTIONS] [--] scripts + +Options: + + -r, --runner RUNNER Testrunner to use, defaults to 'lunit-console'. + -t, --test PATTERN Which tests to run, may contain * or ? wildcards. + --loadonly Only load the tests. + -h, --help Print this help screen. + +Please report bugs to . +]] + return + elseif arg == "--" then + while i < #argv do + i = i + 1; arg = argv[i] + loadtestcase(arg) + end + else + loadtestcase(arg) + end + end + + if doloadonly then + return loadonly() + else + return run(testpatterns) + end +end + +clearstats() + +return lunit diff --git a/bindings/lua/lunitx/lunit/console.lua b/bindings/lua/lunitx/lunit/console.lua new file mode 100644 index 0000000..0ff22a4 --- /dev/null +++ b/bindings/lua/lunitx/lunit/console.lua @@ -0,0 +1,156 @@ + +--[[-------------------------------------------------------------------------- + + This file is part of lunit 0.5. + + For Details about lunit look at: http://www.mroth.net/lunit/ + + Author: Michael Roth + + Copyright (c) 2006-2008 Michael Roth + + 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. + +--]]-------------------------------------------------------------------------- + + + +--[[ + + begin() + run(testcasename, testname) + err(fullname, message, traceback) + fail(fullname, where, message, usermessage) + pass(testcasename, testname) + done() + + Fullname: + testcase.testname + testcase.testname:setupname + testcase.testname:teardownname + +--]] + + +lunit = require "lunit" + +local lunit_console + +if _VERSION >= 'Lua 5.2' then + + lunit_console = setmetatable({},{__index = _ENV}) + _ENV = lunit_console + +else + + module( "lunit-console", package.seeall ) + lunit_console = _M + +end + + + +local function printformat(format, ...) + io.write( string.format(format, ...) ) +end + + +local columns_printed = 0 + +local function writestatus(char) + if columns_printed == 0 then + io.write(" ") + end + if columns_printed == 60 then + io.write("\n ") + columns_printed = 0 + end + io.write(char) + io.flush() + columns_printed = columns_printed + 1 +end + + +local msgs = {} + + +function begin() + local total_tc = 0 + local total_tests = 0 + + msgs = {} -- e + + for tcname in lunit.testcases() do + total_tc = total_tc + 1 + for testname, test in lunit.tests(tcname) do + total_tests = total_tests + 1 + end + end + + printformat("Loaded testsuite with %d tests in %d testcases.\n\n", total_tests, total_tc) +end + + +function run(testcasename, testname) + -- NOP +end + + +function err(fullname, message, traceback) + writestatus("E") + msgs[#msgs+1] = "Error! ("..fullname.."):\n"..message.."\n\t"..table.concat(traceback, "\n\t") .. "\n" +end + + +function fail(fullname, where, message, usermessage) + writestatus("F") + local text = "Failure ("..fullname.."):\n".. + where..": "..message.."\n" + + if usermessage then + text = text .. where..": "..usermessage.."\n" + end + + msgs[#msgs+1] = text +end + + +function pass(testcasename, testname) + writestatus(".") +end + + + +function done() + printformat("\n\n%d Assertions checked.\n", lunit.stats.assertions ) + print() + + for i, msg in ipairs(msgs) do + printformat( "%3d) %s\n", i, msg ) + end + + printformat("Testsuite finished (%d passed, %d failed, %d errors).\n", + lunit.stats.passed, lunit.stats.failed, lunit.stats.errors ) +end + + +return lunit_console + + diff --git a/bindings/lua/lunitx/lunitx.lua b/bindings/lua/lunitx/lunitx.lua new file mode 100644 index 0000000..7656e6a --- /dev/null +++ b/bindings/lua/lunitx/lunitx.lua @@ -0,0 +1,21 @@ +local atexit = require "atexit" +local lunit = require "lunit" + +--for k,v in pairs(debug.getinfo(1,"S")) do print(k,v) end +-- autonameing +-- module("bcrc-test", lunit.testcase, package.seeall) + +atexit(function() + local _, emsg = xpcall(function() + lunit.main(arg) + end, debug.traceback) + if emsg then + print(emsg) + os.exit(1) + end + if lunit.stats.failed > 0 or lunit.stats.errors > 0 then + os.exit(1) + end +end) + +return lunit diff --git a/bindings/lua/table.c b/bindings/lua/table.c new file mode 100644 index 0000000..31b92d2 --- /dev/null +++ b/bindings/lua/table.c @@ -0,0 +1,167 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman + * + * Lua extension that provides access to upb_table. This is an internal-only + * interface and exists for the sole purpose of writing a C code generator in + * Lua that can dump a upb_table as static C initializers. This lets us use + * Lua for convenient string manipulation while saving us from re-implementing + * the upb_table hash function and hash table layout / collision strategy in + * Lua. + * + * Since this is used only as part of the toolchain (and not part of the + * runtime) we do not hold this module to the same stringent requirements as + * the main Lua modules (for example that misbehaving Lua programs cannot + * crash the interpreter). + */ + +#include +#include +#include +#include +#include "lauxlib.h" +#include "bindings/lua/upb.h" +#include "upb/def.h" + +static void lupbtable_setnum(lua_State *L, int tab, const char *key, + lua_Number val) { + lua_pushnumber(L, val); + lua_setfield(L, tab - 1, key); +} + +static void lupbtable_pushval(lua_State *L, upb_value val, upb_ctype_t type) { + switch (type) { + case UPB_CTYPE_INT32: + lua_pushnumber(L, upb_value_getint32(val)); + break; + case UPB_CTYPE_PTR: + lupb_def_pushwrapper(L, upb_value_getptr(val), NULL); + break; + case UPB_CTYPE_CSTR: + lua_pushstring(L, upb_value_getcstr(val)); + break; + default: + luaL_error(L, "Unexpected type: %d", type); + } +} + +// Sets a few fields common to both hash table entries and arrays. +static void lupbtable_setmetafields(lua_State *L, int type, const void *ptr) { + // We tack this onto every entry so we know it even if the entries + // don't stay with the table. + lua_pushnumber(L, type); + lua_setfield(L, -2, "valtype"); + + // Set this to facilitate linking. + lua_pushlightuserdata(L, (void*)ptr); + lua_setfield(L, -2, "ptr"); +} + +static void lupbtable_pushent(lua_State *L, const upb_tabent *e, + bool inttab, int type) { + lua_newtable(L); + if (!upb_tabent_isempty(e)) { + if (inttab) { + lua_pushnumber(L, e->key.num); + } else { + lua_pushstring(L, e->key.str); + } + lua_setfield(L, -2, "key"); + lupbtable_pushval(L, e->val, type); + lua_setfield(L, -2, "value"); + } + lua_pushlightuserdata(L, (void*)e->next); + lua_setfield(L, -2, "next"); + lupbtable_setmetafields(L, type, e); +} + +// Dumps the shared part of upb_table into a Lua table. +static void lupbtable_pushtable(lua_State *L, const upb_table *t, bool inttab) { + lua_newtable(L); + lupbtable_setnum(L, -1, "count", t->count); + lupbtable_setnum(L, -1, "mask", t->mask); + lupbtable_setnum(L, -1, "type", t->type); + lupbtable_setnum(L, -1, "size_lg2", t->size_lg2); + + lua_newtable(L); + for (int i = 0; i < upb_table_size(t); i++) { + lupbtable_pushent(L, &t->entries[i], inttab, t->type); + lua_rawseti(L, -2, i + 1); + } + lua_setfield(L, -2, "entries"); +} + +// Dumps a upb_inttable to a Lua table. +static void lupbtable_pushinttable(lua_State *L, const upb_inttable *t) { + lupbtable_pushtable(L, &t->t, true); + lupbtable_setnum(L, -1, "array_size", t->array_size); + lupbtable_setnum(L, -1, "array_count", t->array_count); + + lua_newtable(L); + for (int i = 0; i < t->array_size; i++) { + lua_newtable(L); + if (upb_arrhas(t->array[i])) { + lupbtable_pushval(L, t->array[i], t->t.type); + lua_setfield(L, -2, "val"); + } + lupbtable_setmetafields(L, t->t.type, &t->array[i]); + lua_rawseti(L, -2, i + 1); + } + lua_setfield(L, -2, "array"); +} + +static void lupbtable_pushstrtable(lua_State *L, const upb_strtable *t) { + lupbtable_pushtable(L, &t->t, false); +} + +static int lupbtable_msgdef_itof(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lupbtable_pushinttable(L, &m->itof); + return 1; +} + +static int lupbtable_msgdef_ntof(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lupbtable_pushstrtable(L, &m->ntof); + return 1; +} + +static int lupbtable_enumdef_iton(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + lupbtable_pushinttable(L, &e->iton); + return 1; +} + +static int lupbtable_enumdef_ntoi(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + lupbtable_pushstrtable(L, &e->ntoi); + return 1; +} + +static void lupbtable_setfieldi(lua_State *L, const char *field, int i) { + lua_pushnumber(L, i); + lua_setfield(L, -2, field); +} + +static const struct luaL_Reg lupbtable_toplevel_m[] = { + {"msgdef_itof", lupbtable_msgdef_itof}, + {"msgdef_ntof", lupbtable_msgdef_ntof}, + {"enumdef_iton", lupbtable_enumdef_iton}, + {"enumdef_ntoi", lupbtable_enumdef_ntoi}, + {NULL, NULL} +}; + +int luaopen_upbtable(lua_State *L) { + lupb_newlib(L, "upb.table", lupbtable_toplevel_m); + + // We define these here because they are not public (at least at the moment). + lupbtable_setfieldi(L, "CTYPE_PTR", UPB_CTYPE_PTR); + lupbtable_setfieldi(L, "CTYPE_INT32", UPB_CTYPE_INT32); + + lua_pushlightuserdata(L, NULL); + lua_setfield(L, -2, "NULL"); + + return 1; // Return a single Lua value, the package table created above. +} diff --git a/bindings/lua/test.lua b/bindings/lua/test.lua index 42bce25..6b162a9 100644 --- a/bindings/lua/test.lua +++ b/bindings/lua/test.lua @@ -1,109 +1,262 @@ -require "upb" +local upb = require "upb" +local lunit = require "lunitx" -symtab = upb.SymbolTable{ - upb.MessageDef{fqname="A", fields={ - upb.FieldDef{name="a", type=upb.TYPE_INT32, number=1}, - upb.FieldDef{name="b", type=upb.TYPE_DOUBLE, number=2}} +if _VERSION >= 'Lua 5.2' then + _ENV = lunit.module("testupb", "seeall") +else + module("testupb", lunit.testcase, package.seeall) +end + +function test_fielddef() + local f = upb.FieldDef() + assert_false(f:is_frozen()) + assert_nil(f:number()) + assert_nil(f:name()) + assert_equal(upb.LABEL_OPTIONAL, f:label()) + + f:set_name("foo_field") + f:set_number(3) + f:set_label(upb.LABEL_REPEATED) + f:set_type(upb.TYPE_FLOAT) + + assert_equal("foo_field", f:name()) + assert_equal(3, f:number()) + assert_equal(upb.LABEL_REPEATED, f:label()) + assert_equal(upb.TYPE_FLOAT, f:type()) + + local f2 = upb.FieldDef{ + name = "foo", number = 5, type = upb.TYPE_DOUBLE, label = upb.LABEL_REQUIRED } -} - -symtab = upb.SymbolTable{ - upb.MessageDef{fqname="A", fields={ - upb.FieldDef{name="a", type=upb.TYPE_INT32, number=1}, - upb.FieldDef{name="b", type=upb.TYPE_DOUBLE, number=2}} - }, - upb.MessageDef{fqname="B"} -} -A, B, C = symtab:lookup("A", "B") -print(A) -print(B) -print(C) - -a = A() -a2 = upb.Message(A) -print("YO! a.a=" .. tostring(a.a) .. ", a2.a=" .. tostring(a2.a)) -a.a = 2 -a2.a = 3 -print("YO! a.a=" .. tostring(a.a) .. ", a2.a=" .. tostring(a2.a)) - -A = symtab:lookup("A") -if not A then - error("Could not find A") + + assert_equal("foo", f2:name()) + assert_equal(5, f2:number()) + assert_equal(upb.TYPE_DOUBLE, f2:type()) + assert_equal(upb.LABEL_REQUIRED, f2:label()) end -f = io.open("../../upb/descriptor.pb") -if not f then - error("Couldn't open descriptor.pb, try running 'make descriptorgen'") +function test_enumdef() + local e = upb.EnumDef() + assert_equal(0, #e) + assert_nil(e:value(5)) + assert_nil(e:value("NONEXISTENT_NAME")) + + for name, value in e:values() do + fail() + end + + e:add("VAL1", 1) + e:add("VAL2", 2) + + local values = {} + for name, value in e:values() do + values[name] = value + end + + assert_equal(1, values["VAL1"]) + assert_equal(2, values["VAL2"]) + + local e2 = upb.EnumDef{ + values = { + {"FOO", 1}, + {"BAR", 77}, + } + } + + assert_equal(1, e2:value("FOO")) + assert_equal(77, e2:value("BAR")) + assert_equal("FOO", e2:value(1)) + assert_equal("BAR", e2:value(77)) end -symtab:parsedesc(f:read("*all")) -symtab:load_descriptor() -symtab:load_descriptor_file() -upb.pb.load_descriptor(f:read("*all")) +function test_empty_msgdef() + local md = upb.MessageDef() + assert_nil(md:full_name()) -- Def without name is anonymous. + assert_false(md:is_frozen()) + assert_equal(0, #md) + assert_nil(md:field("nonexistent_field")) + assert_nil(md:field(3)) + for field in md:fields() do + fail() + end + + upb.freeze(md) + assert_true(md:is_frozen()) + assert_equal(0, #md) + assert_nil(md:field("nonexistent_field")) + assert_nil(md:field(3)) + for field in md:fields() do + fail() + end +end + +function test_msgdef_constructor() + local f1 = upb.FieldDef{name = "field1", number = 7, type = upb.TYPE_INT32} + local f2 = upb.FieldDef{name = "field2", number = 8, type = upb.TYPE_INT32} + local md = upb.MessageDef{ + full_name = "TestMessage", + fields = {f1, f2} + } + assert_equal("TestMessage", md:full_name()) + assert_false(md:is_frozen()) + assert_equal(2, #md) + assert_equal(f1, md:field("field1")) + assert_equal(f2, md:field("field2")) + assert_equal(f1, md:field(7)) + assert_equal(f2, md:field(8)) + local count = 0 + local found = {} + for field in md:fields() do + count = count + 1 + found[field] = true + end + assert_equal(2, count) + assert_true(found[f1]) + assert_true(found[f2]) -upb.pb.load_descriptor_file("../../src/descriptor.pb", symtab) + upb.freeze(md) +end + +function test_msgdef_setters() + local md = upb.MessageDef() + md:set_full_name("Message1") + assert_equal("Message1", md:full_name()) + local f = upb.FieldDef{name = "field1", number = 3, type = upb.TYPE_DOUBLE} + md:add{f} + assert_equal(1, #md) + assert_equal(f, md:field("field1")) +end + +function test_msgdef_errors() + assert_error(function() upb.MessageDef{bad_initializer_key = 5} end) + local md = upb.MessageDef() + assert_error(function() + -- Duplicate field number. + upb.MessageDef{ + fields = { + upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, + upb.FieldDef{name = "field2", number = 1, type = upb.TYPE_INT32} + } + } + end) + assert_error(function() + -- Duplicate field name. + upb.MessageDef{ + fields = { + upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, + upb.FieldDef{name = "field1", number = 2, type = upb.TYPE_INT32} + } + } + end) + + -- attempt to set a name with embedded NULLs. + assert_error_match("names cannot have embedded NULLs", function() + md:set_full_name("abc\0def") + end) + + upb.freeze(md) + -- Attempt to mutate frozen MessageDef. + -- TODO(haberman): better error message and test for message. + assert_error(function() + md:add{upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}} + end) + assert_error(function() + md:set_full_name("abc") + end) + + -- Attempt to freeze a msgdef without freezing its subdef. + assert_error_match("is not frozen or being frozen", function() + m1 = upb.MessageDef() + upb.freeze( + upb.MessageDef{ + fields = { + upb.FieldDef{name = "f1", number = 1, type = upb.TYPE_MESSAGE, + subdef = m1} + } + } + ) + end) +end + +function test_symtab() + local empty = upb.SymbolTable() + assert_equal(0, #empty:getdefs(upb.DEF_ANY)) + + local symtab = upb.SymbolTable{ + upb.MessageDef{full_name = "TestMessage"}, + upb.MessageDef{full_name = "ContainingMessage", fields = { + upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, + upb.FieldDef{name = "field2", number = 2, type = upb.TYPE_MESSAGE, + subdef_name = ".TestMessage"} + } + } + } + + local msgdef1 = symtab:lookup("TestMessage") + local msgdef2 = symtab:lookup("ContainingMessage") + assert_not_nil(msgdef1) + assert_not_nil(msgdef2) + assert_equal(msgdef1, msgdef2:field("field2"):subdef()) + assert_true(msgdef1:is_frozen()) + assert_true(msgdef2:is_frozen()) + + symtab:add{ + upb.MessageDef{full_name = "ContainingMessage2", fields = { + upb.FieldDef{name = "field5", number = 5, type = upb.TYPE_MESSAGE, + subdef = msgdef2} + } + } + } + + local msgdef3 = symtab:lookup("ContainingMessage2") + assert_not_nil(msgdef3) + assert_equal(msgdef3:field("field5"):subdef(), msgdef2) +end -f = io.open("../../benchmarks/google_messages.proto.pb") -if not f then - error("Couldn't open google_messages.proto.pb, try running 'make benchmarks'") +-- Lua 5.1 and 5.2 have slightly different semantics for how a finalizer +-- can be defined in Lua. +if _VERSION >= 'Lua 5.2' then + function defer(fn) + setmetatable({}, { __gc = fn }) + end +else + function defer(fn) + getmetatable(newproxy(true)).__gc = fn + end end -symtab:parsedesc(f:read("*all")) -for _, def in ipairs(symtab:getdefs(-1)) do - print(def:name()) +function test_finalizer() + -- Tests that we correctly handle a call into an already-finalized object. + -- Collectible objects are finalized in the opposite order of creation. + do + local t = {} + defer(function() + assert_error_match("called into dead def", function() + -- Generic def call. + t[1]:full_name() + end) + assert_error_match("called into dead msgdef", function() + -- Specific msgdef call. + t[1]:add() + end) + assert_error_match("called into dead enumdef", function() + t[2]:values() + end) + assert_error_match("called into dead fielddef", function() + t[3]:number() + end) + assert_error_match("called into dead symtab", + function() t[4]:lookup() + end) + end) + t = { + upb.MessageDef(), + upb.EnumDef(), + upb.FieldDef(), + upb.SymbolTable(), + } + end + collectgarbage() end -SpeedMessage1 = symtab:lookup("benchmarks.SpeedMessage1") -SpeedMessage2 = symtab:lookup("benchmarks.SpeedMessage2") -print(SpeedMessage1:name()) - -msg = MyType() -msg:Decode(str) - -msg:DecodeJSON(str) - -msg = upb.pb.decode(str, MyType) -str = upb.pb.encode(msg) - -msg = upb.pb.decode_text(str, MyType) -str = upb.pb.encode_text(msg) - -upb.clear(msg) -upb.msgdef(msg) -upb.has(msg, "foo_bar") - -msg = upb.json.decode(str, MyType) - -msg = upb.pb.DecodeText(str) -msg = upb.pb.EncodeText(msg) -upb. - -upb.pb.decode_into(msg, str) - -str = upb.json.Encode(msg) -upb.json.DecodeInto(msg, str) -f = assert(io.open("../../benchmarks/google_message1.dat")) -msg:Parse(f:read("*all")) -print(msg:ToText()) -print(upb.json.encode(msg)) - -msg = SpeedMessage2() -f = assert(io.open("../../benchmarks/google_message2.dat")) -msg:Parse(f:read("*all")) -print(msg:ToText()) ---msg:Serialize() ---msg:FromText(str) --- print(msg.field129) --- print(msg.field271) ---print(msg.field15.field15) ---msg.field15.field15 = "my override" ---print(msg.field15.field15) --- print(msg.field1) --- print(msg.field1) --- msg.field1 = "YEAH BABY!" --- print(msg.field1) --- print(msg.field129) --- msg.field129 = 5 --- print(msg.field129) ---]] +lunit.main() diff --git a/bindings/lua/upb.c b/bindings/lua/upb.c index 4cce4b6..1a1d7c0 100644 --- a/bindings/lua/upb.c +++ b/bindings/lua/upb.c @@ -4,96 +4,85 @@ * Copyright (c) 2009 Google Inc. See LICENSE for details. * Author: Josh Haberman * - * A Lua extension for upb. + * A Lua extension for upb. Exposes only the core library + * (sub-libraries are exposed in other extensions). */ -#include -#include #include +#include +#include +#include #include "lauxlib.h" -#include "upb/def.h" -#include "upb/msg.h" +#include "bindings/lua/upb.h" +#include "upb/bytestream.h" #include "upb/pb/glue.h" -#if LUA_VERSION_NUM == 501 -#define lua_rawlen lua_objlen -#endif +// Lua metatable types. +#define LUPB_MSGDEF "lupb.msgdef" +#define LUPB_ENUMDEF "lupb.enumdef" +#define LUPB_FIELDDEF "lupb.fielddef" +#define LUPB_SYMTAB "lupb.symtab" -static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; } +// Other table constants. +#define LUPB_OBJCACHE "lupb.objcache" -static bool lupb_isint(double n) { return (double)(int)n == n; } +#if LUA_VERSION_NUM == 501 -static uint8_t lupb_touint8(lua_State *L, int narg, const char *name) { - lua_Number n = lua_tonumber(L, narg); - if (n > UINT8_MAX || n < 0 || rint(n) != n) - luaL_error(L, "Invalid %s", name); - return n; +// Taken from Lua 5.2's source. +void *luaL_testudata(lua_State *L, int ud, const char *tname) { + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + luaL_getmetatable(L, tname); /* get correct metatable */ + if (!lua_rawequal(L, -1, -2)) /* not the same? */ + p = NULL; /* value is a userdata with wrong metatable */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + return NULL; /* value is not a userdata with a metatable */ } -static uint32_t lupb_touint32(lua_State *L, int narg, const char *name) { - lua_Number n = lua_tonumber(L, narg); - if (n > UINT32_MAX || n < 0 || rint(n) != n) - luaL_error(L, "Invalid %s", name); - return n; +#elif LUA_VERSION_NUM == 502 + +int luaL_typerror(lua_State *L, int narg, const char *tname) { + const char *msg = lua_pushfstring(L, "%s expected, got %s", + tname, luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); } -static void lupb_pushstring(lua_State *L, const upb_strref *ref) { - if (ref->ptr) { - lua_pushlstring(L, ref->ptr, ref->len); - } else { - // Lua requires a continguous string; must copy+allocate. - char *str = upb_strref_dup(ref); - lua_pushlstring(L, str, ref->len); - free(str); - } +#else +#error Only Lua 5.1 and 5.2 are supported +#endif + +const char *lupb_checkname(lua_State *L, int narg) { + size_t len; + const char *name = luaL_checklstring(L, narg, &len); + if (strlen(name) != len) + luaL_error(L, "names cannot have embedded NULLs"); + return name; } -static void lupb_pushvalue(lua_State *L, upb_value val, upb_fielddef *f) { - switch (f->type) { - case UPB_TYPE(INT32): - case UPB_TYPE(SINT32): - case UPB_TYPE(SFIXED32): - case UPB_TYPE(ENUM): - lua_pushnumber(L, upb_value_getint32(val)); break; - case UPB_TYPE(INT64): - case UPB_TYPE(SINT64): - case UPB_TYPE(SFIXED64): - lua_pushnumber(L, upb_value_getint64(val)); break; - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): - lua_pushnumber(L, upb_value_getuint32(val)); break; - case UPB_TYPE(UINT64): - case UPB_TYPE(FIXED64): - lua_pushnumber(L, upb_value_getuint64(val)); break; - case UPB_TYPE(DOUBLE): - lua_pushnumber(L, upb_value_getdouble(val)); break; - case UPB_TYPE(FLOAT): - lua_pushnumber(L, upb_value_getfloat(val)); break; - case UPB_TYPE(BOOL): - lua_pushboolean(L, upb_value_getbool(val)); break; - default: luaL_error(L, "internal error"); - } +static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; } + +static uint32_t lupb_checkint32(lua_State *L, int narg, const char *name) { + lua_Number n = lua_tonumber(L, narg); + if (n > INT32_MAX || n < INT32_MIN || rint(n) != n) + luaL_error(L, "Invalid %s", name); + return n; } -// Returns a scalar value (ie. not a submessage) as a upb_value. -static upb_value lupb_getvalue(lua_State *L, int narg, upb_fielddef *f, - upb_strref *ref) { - assert(!upb_issubmsg(f)); +// Converts a number or bool from Lua -> upb_value. +static upb_value lupb_getvalue(lua_State *L, int narg, upb_fieldtype_t type) { upb_value val; - if (upb_fielddef_type(f) == UPB_TYPE(BOOL)) { + if (type == UPB_TYPE(BOOL)) { if (!lua_isboolean(L, narg)) luaL_error(L, "Must explicitly pass true or false for boolean fields"); upb_value_setbool(&val, lua_toboolean(L, narg)); - } else if (upb_fielddef_type(f) == UPB_TYPE(STRING)) { - size_t len; - ref->ptr = luaL_checklstring(L, narg, &len); - ref->len = len; - upb_value_setstrref(&val, ref); } else { // Numeric type. - lua_Number num = 0; - num = luaL_checknumber(L, narg); - switch (upb_fielddef_type(f)) { + lua_Number num = luaL_checknumber(L, narg); + switch (type) { case UPB_TYPE(INT32): case UPB_TYPE(SINT32): case UPB_TYPE(SFIXED32): @@ -133,374 +122,743 @@ static upb_value lupb_getvalue(lua_State *L, int narg, upb_fielddef *f, luaL_error(L, "Cannot convert %f to float", num); upb_value_setfloat(&val, num); break; + default: luaL_error(L, "invalid type"); } } return val; } -static void lupb_typecheck(lua_State *L, int narg, upb_fielddef *f) { - upb_strref ref; - lupb_getvalue(L, narg, f, &ref); +// Converts a upb_value -> Lua value. +static void lupb_pushvalue(lua_State *L, upb_value val, upb_fieldtype_t type) { + switch (type) { + case UPB_TYPE(INT32): + case UPB_TYPE(SINT32): + case UPB_TYPE(SFIXED32): + case UPB_TYPE(ENUM): + lua_pushnumber(L, upb_value_getint32(val)); break; + case UPB_TYPE(INT64): + case UPB_TYPE(SINT64): + case UPB_TYPE(SFIXED64): + lua_pushnumber(L, upb_value_getint64(val)); break; + case UPB_TYPE(UINT32): + case UPB_TYPE(FIXED32): + lua_pushnumber(L, upb_value_getuint32(val)); break; + case UPB_TYPE(UINT64): + case UPB_TYPE(FIXED64): + lua_pushnumber(L, upb_value_getuint64(val)); break; + case UPB_TYPE(DOUBLE): + lua_pushnumber(L, upb_value_getdouble(val)); break; + case UPB_TYPE(FLOAT): + lua_pushnumber(L, upb_value_getfloat(val)); break; + case UPB_TYPE(BOOL): + lua_pushboolean(L, upb_value_getbool(val)); break; + case UPB_TYPE(STRING): + case UPB_TYPE(BYTES): { + const upb_byteregion *r = upb_value_getbyteregion(val); + size_t len; + const char *str = upb_byteregion_getptr(r, 0, &len); + lua_pushlstring(L, str, len); + } + default: luaL_error(L, "internal error"); + } } -//static void lupb_msg_getorcreate(lua_State *L, upb_msg *msg, upb_msgdef *md); -static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f); -static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg); -static void lupb_msg_pushnew(lua_State *L, const void *md); - void lupb_checkstatus(lua_State *L, upb_status *s) { if (!upb_ok(s)) { - // Need to copy the string to the stack, so we can free it and not leak - // it (since luaL_error() does not return). - const char *str = upb_status_getstr(s); - char buf[strlen(str)+1]; - strcpy(buf, str); + lua_pushstring(L, upb_status_getstr(s)); + upb_status_uninit(s); + lua_error(L); + } else { upb_status_uninit(s); - luaL_error(L, "%s", buf); } - upb_status_uninit(s); } -/* object cache ***************************************************************/ +/* refcounted *****************************************************************/ + +// All upb objects that use upb_refcounted share a common Lua userdata +// representation and a common scheme for caching Lua wrapper object. They do +// however have different metatables. Objects are cached in a weak table +// indexed by the C pointer of the object they are caching. + +typedef union { + const upb_refcounted *refcounted; + const upb_def *def; + upb_symtab *symtab; +} lupb_refcounted; -// We cache all the lua objects (userdata) we vend in a weak table, indexed by -// the C pointer of the object they are caching. +static bool lupb_refcounted_pushwrapper(lua_State *L, const upb_refcounted *obj, + const char *type, const void *owner) { + if (obj == NULL) { + lua_pushnil(L); + return false; + } -static void *lupb_cache_getorcreate_size( - lua_State *L, void *cobj, const char *type, size_t size) { // Lookup our cache in the registry (we don't put our objects in the registry // directly because we need our cache to be a weak table). - void **obj = NULL; - lua_getfield(L, LUA_REGISTRYINDEX, "upb.objcache"); + lupb_refcounted *ud = NULL; + lua_getfield(L, LUA_REGISTRYINDEX, LUPB_OBJCACHE); assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. - lua_pushlightuserdata(L, cobj); + lua_pushlightuserdata(L, (void*)obj); lua_rawget(L, -2); // Stack: objcache, cached value. - if (lua_isnil(L, -1)) { + bool create = lua_isnil(L, -1) || + // A corner case: it is possible for the value to be GC'd + // already, in which case we should evict this entry and create + // a new one. + ((lupb_refcounted*)lua_touserdata(L, -1))->refcounted == NULL; + if (create) { // Remove bad cached value and push new value. lua_pop(L, 1); + // We take advantage of the fact that all of our objects are currently a // single pointer, and thus have the same layout. - obj = lua_newuserdata(L, size); - *obj = cobj; + // TODO: this probably violates aliasing. + ud = lua_newuserdata(L, sizeof(lupb_refcounted)); + ud->refcounted = obj; + upb_refcounted_donateref(obj, owner, ud); + luaL_getmetatable(L, type); assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. lua_setmetatable(L, -2); // Set it in the cache. - lua_pushlightuserdata(L, cobj); + lua_pushlightuserdata(L, (void*)obj); lua_pushvalue(L, -2); lua_rawset(L, -4); + } else { + // Existing wrapper obj already has a ref. + ud = lua_touserdata(L, -1); + upb_refcounted_checkref(obj, ud); + if (owner) + upb_refcounted_unref(obj, owner); } lua_insert(L, -2); lua_pop(L, 1); - return obj; -} - -// Most types are just 1 pointer and can use this helper. -static bool lupb_cache_getorcreate(lua_State *L, void *cobj, const char *type) { - return lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL; + return create; } -static void lupb_cache_create(lua_State *L, void *cobj, const char *type) { - bool created = - lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL; - (void)created; // For NDEBUG - assert(created); +static void lupb_refcounted_pushnewrapper(lua_State *L, upb_refcounted *obj, + const char *type, const void *owner) { + bool created = lupb_refcounted_pushwrapper(L, obj, type, owner); + UPB_ASSERT_VAR(created, created == true); } /* lupb_def *******************************************************************/ -// All the def types share the same C layout, even though they are different Lua -// types with different metatables. -typedef struct { - upb_def *def; -} lupb_def; - -static lupb_def *lupb_def_check(lua_State *L, int narg) { - void *ldef = luaL_checkudata(L, narg, "upb.msgdef"); - if (!ldef) ldef = luaL_checkudata(L, narg, "upb.enumdef"); - if (!ldef) luaL_typerror(L, narg, "upb def"); - return ldef; -} - -static void lupb_def_getorcreate(lua_State *L, const upb_def *def, int owned) { - bool created = false; - switch(def->type) { - case UPB_DEF_MSG: - created = lupb_cache_getorcreate(L, (void*)def, "upb.msgdef"); - break; - case UPB_DEF_ENUM: - created = lupb_cache_getorcreate(L, (void*)def, "upb.enumdef"); - break; - default: - luaL_error(L, "unknown deftype %d", def->type); +static const upb_def *lupb_def_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_testudata(L, narg, LUPB_MSGDEF); + if (!r) r = luaL_testudata(L, narg, LUPB_ENUMDEF); + if (!r) r = luaL_testudata(L, narg, LUPB_FIELDDEF); + if (!r) luaL_typerror(L, narg, "upb def"); + if (!r->refcounted) luaL_error(L, "called into dead def"); + return r->def; +} + +static upb_def *lupb_def_checkmutable(lua_State *L, int narg) { + const upb_def *def = lupb_def_check(L, narg); + if (upb_def_isfrozen(def)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_def*)def; +} + +bool lupb_def_pushwrapper(lua_State *L, const upb_def *def, const void *owner) { + if (def == NULL) { + lua_pushnil(L); + return false; } - if (!owned && created) { - upb_def_ref(def); - } else if (owned && !created) { - upb_def_unref(def); + + const char *type = NULL; + switch (def->type) { + case UPB_DEF_MSG: type = LUPB_MSGDEF; break; + case UPB_DEF_ENUM: type = LUPB_ENUMDEF; break; + case UPB_DEF_FIELD: type = LUPB_FIELDDEF; break; + default: luaL_error(L, "unknown deftype %d", def->type); } + return lupb_refcounted_pushwrapper(L, upb_upcast(def), type, owner); } +void lupb_def_pushnewrapper(lua_State *L, const upb_def *def, + const void *owner) { + bool created = lupb_def_pushwrapper(L, def, owner); + UPB_ASSERT_VAR(created, created == true); +} -/* lupb_fielddef **************************************************************/ +static int lupb_def_type(lua_State *L) { + const upb_def *def = lupb_def_check(L, 1); + lua_pushnumber(L, upb_def_type(def)); + return 1; +} -typedef struct { - upb_fielddef *field; -} lupb_fielddef; - -static lupb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { - lupb_fielddef *f = luaL_checkudata(L, narg, "upb.fielddef"); - if (!f) luaL_typerror(L, narg, "upb fielddef"); - return f; -} - -static int lupb_fielddef_index(lua_State *L) { - lupb_fielddef *f = lupb_fielddef_check(L, 1); - const char *str = luaL_checkstring(L, 2); - if (streql(str, "name")) { - lua_pushstring(L, upb_fielddef_name(f->field)); - } else if (streql(str, "number")) { - lua_pushinteger(L, upb_fielddef_number(f->field)); - } else if (streql(str, "type")) { - lua_pushinteger(L, upb_fielddef_type(f->field)); - } else if (streql(str, "label")) { - lua_pushinteger(L, upb_fielddef_label(f->field)); - } else if (streql(str, "subdef")) { - lupb_def_getorcreate(L, upb_fielddef_subdef(f->field), false); - } else if (streql(str, "msgdef")) { - lupb_def_getorcreate(L, UPB_UPCAST(upb_fielddef_msgdef(f->field)), false); - } else { - luaL_error(L, "Invalid fielddef member '%s'", str); - } +static int lupb_def_isfrozen(lua_State *L) { + const upb_def *def = lupb_def_check(L, 1); + lua_pushboolean(L, upb_def_isfrozen(def)); return 1; } -static void lupb_fielddef_set(lua_State *L, upb_fielddef *f, - const char *field, int narg) { - if (!upb_fielddef_ismutable(f)) luaL_error(L, "fielddef is not mutable."); - if (streql(field, "name")) { - const char *name = lua_tostring(L, narg); - if (!name || !upb_fielddef_setname(f, name)) - luaL_error(L, "Invalid name"); - } else if (streql(field, "number")) { - if (!upb_fielddef_setnumber(f, lupb_touint32(L, narg, "number"))) - luaL_error(L, "Invalid number"); - } else if (streql(field, "type")) { - if (!upb_fielddef_settype(f, lupb_touint8(L, narg, "type"))) - luaL_error(L, "Invalid type"); - } else if (streql(field, "label")) { - if (!upb_fielddef_setlabel(f, lupb_touint8(L, narg, "label"))) - luaL_error(L, "Invalid label"); - } else if (streql(field, "type_name")) { - const char *name = lua_tostring(L, narg); - if (!name || !upb_fielddef_settypename(f, name)) - luaL_error(L, "Invalid type_name"); - } else if (streql(field, "default_value")) { - if (!upb_fielddef_type(f)) - luaL_error(L, "Must set type before setting default_value"); - upb_strref ref; - upb_fielddef_setdefault(f, lupb_getvalue(L, narg, f, &ref)); +static int lupb_def_fullname(lua_State *L) { + const upb_def *def = lupb_def_check(L, 1); + lua_pushstring(L, upb_def_fullname(def)); + return 1; +} + +static int lupb_def_setfullname(lua_State *L) { + upb_def *def = lupb_def_checkmutable(L, 1); + const char *name = lupb_checkname(L, 2); + upb_def_setfullname(def, name); + return 0; +} + +#define LUPB_COMMON_DEF_METHODS \ + {"def_type", lupb_def_type}, \ + {"full_name", lupb_def_fullname}, \ + {"is_frozen", lupb_def_isfrozen}, \ + {"set_full_name", lupb_def_setfullname}, \ + + +/* lupb_fielddef **************************************************************/ + +static const upb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_FIELDDEF); + if (!r) luaL_typerror(L, narg, "upb fielddef"); + if (!r->refcounted) luaL_error(L, "called into dead fielddef"); + return upb_downcast_fielddef(r->def); +} + +static upb_fielddef *lupb_fielddef_checkmutable(lua_State *L, int narg) { + const upb_fielddef *f = lupb_fielddef_check(L, narg); + if (upb_fielddef_isfrozen(f)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_fielddef*)f; +} + +// Setter functions; these are called by both the constructor and the individual +// setter API calls like field:set_type(). + +static void lupb_fielddef_dosetdefault(lua_State *L, upb_fielddef *f, + int narg) { + int type = lua_type(L, narg); + upb_fieldtype_t upbtype = upb_fielddef_type(f); + if (type == LUA_TSTRING) { + if (!upb_fielddef_isstring(f) && upbtype != UPB_TYPE(ENUM)) + luaL_argerror(L, narg, "field does not expect a string default"); + size_t len; + const char *str = lua_tolstring(L, narg, &len); + if (!upb_fielddef_setdefaultstr(f, str, len)) + luaL_argerror(L, narg, "invalid default string for enum"); } else { - luaL_error(L, "Cannot set fielddef member '%s'", field); + upb_fielddef_setdefault(f, lupb_getvalue(L, narg, upbtype)); } } +static void lupb_fielddef_dosetlabel(lua_State *L, upb_fielddef *f, int narg) { + upb_label_t label = luaL_checknumber(L, narg); + if (!upb_fielddef_setlabel(f, label)) + luaL_argerror(L, narg, "invalid field label"); +} + +static void lupb_fielddef_dosetnumber(lua_State *L, upb_fielddef *f, int narg) { + int32_t n = luaL_checknumber(L, narg); + if (!upb_fielddef_setnumber(f, n)) + luaL_argerror(L, narg, "invalid field number"); +} + +static void lupb_fielddef_dosetsubdef(lua_State *L, upb_fielddef *f, int narg) { + const upb_def *def = NULL; + if (!lua_isnil(L, narg)) + def = lupb_def_check(L, narg); + if (!upb_fielddef_setsubdef(f, def)) + luaL_argerror(L, narg, "invalid subdef for this field"); +} + +static void lupb_fielddef_dosetsubdefname(lua_State *L, upb_fielddef *f, + int narg) { + const char *name = NULL; + if (!lua_isnil(L, narg)) + name = lupb_checkname(L, narg); + if (!upb_fielddef_setsubdefname(f, name)) + luaL_argerror(L, narg, "field type does not expect a subdef"); +} + +static void lupb_fielddef_dosettype(lua_State *L, upb_fielddef *f, int narg) { + int32_t type = luaL_checknumber(L, narg); + if (!upb_fielddef_settype(f, type)) + luaL_argerror(L, narg, "invalid field type"); +} + +// Setter API calls. These use the setter functions above. + +static int lupb_fielddef_setdefault(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetdefault(L, f, 2); + return 0; +} + +static int lupb_fielddef_setlabel(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetlabel(L, f, 2); + return 0; +} + +static int lupb_fielddef_setnumber(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetnumber(L, f, 2); + return 0; +} + +static int lupb_fielddef_setsubdef(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetsubdef(L, f, 2); + return 0; +} + +static int lupb_fielddef_setsubdefname(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetsubdefname(L, f, 2); + return 0; +} + +static int lupb_fielddef_settype(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosettype(L, f, 2); + return 0; +} + +// Constructor and other methods. + static int lupb_fielddef_new(lua_State *L) { - upb_fielddef *f = upb_fielddef_new(); - lupb_cache_create(L, f, "upb.fielddef"); + upb_fielddef *f = upb_fielddef_new(&f); + int narg = lua_gettop(L); + + lupb_def_pushnewrapper(L, upb_upcast(f), &f); - if (lua_gettop(L) == 0) return 1; + if (narg == 0) return 1; // User can specify initialization values like so: // upb.FieldDef{label=upb.LABEL_REQUIRED, name="my_field", number=5, // type=upb.TYPE_INT32, default_value=12, type_name="Foo"} luaL_checktype(L, 1, LUA_TTABLE); - // Iterate over table. - lua_pushnil(L); // first key - while (lua_next(L, 1)) { + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { luaL_checktype(L, -2, LUA_TSTRING); const char *key = lua_tostring(L, -2); - lupb_fielddef_set(L, f, key, -1); - lua_pop(L, 1); + int v = -1; + if (streql(key, "name")) upb_fielddef_setname(f, lupb_checkname(L, v)); + else if (streql(key, "number")) lupb_fielddef_dosetnumber(L, f, v); + else if (streql(key, "type")) lupb_fielddef_dosettype(L, f, v); + else if (streql(key, "label")) lupb_fielddef_dosetlabel(L, f, v); + else if (streql(key, "default_value")) ; // Defer to second pass. + else if (streql(key, "subdef")) ; // Defer to second pass. + else if (streql(key, "subdef_name")) ; // Defer to second pass. + else luaL_error(L, "Cannot set fielddef member '%s'", key); } + + // Have to do these in a second pass because these depend on the type, so we + // have to make sure the type is set if the user specified one. + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { + const char *key = lua_tostring(L, -2); + int v = -1; + if (streql(key, "default_value")) lupb_fielddef_dosetdefault(L, f, v); + else if (streql(key, "subdef")) lupb_fielddef_dosetsubdef(L, f, v); + else if (streql(key, "subdef_name")) lupb_fielddef_dosetsubdefname(L, f, v); + } + return 1; } -static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f) { - bool created = lupb_cache_getorcreate(L, f, "upb.fielddef"); - if (created) upb_fielddef_ref(f); +static int lupb_fielddef_default(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + upb_fieldtype_t type = upb_fielddef_type(f); + if (upb_fielddef_default_is_symbolic(f)) + type = UPB_TYPE(STRING); + lupb_pushvalue(L, upb_fielddef_default(f), type); + return 1; } -static int lupb_fielddef_newindex(lua_State *L) { - lupb_fielddef *f = lupb_fielddef_check(L, 1); - lupb_fielddef_set(L, f->field, luaL_checkstring(L, 2), 3); - return 0; +static int lupb_fielddef_label(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushnumber(L, upb_fielddef_label(f)); + return 1; +} + +static int lupb_fielddef_number(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + int32_t num = upb_fielddef_number(f); + if (num) + lua_pushnumber(L, num); + else + lua_pushnil(L); + return 1; +} + +static int lupb_fielddef_selectorbase(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + if (!upb_fielddef_isfrozen(f)) + luaL_error(L, "_selectorbase is only defined for frozen fielddefs"); + lua_pushnumber(L, f->selector_base); + return 1; +} + +static int lupb_fielddef_hassubdef(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushboolean(L, upb_fielddef_hassubdef(f)); + return 1; +} + +static int lupb_fielddef_msgdef(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lupb_def_pushwrapper(L, upb_upcast(upb_fielddef_msgdef(f)), NULL); + return 1; +} + +static int lupb_fielddef_subdef(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + if (!upb_fielddef_hassubdef(f)) + luaL_error(L, "Tried to get subdef of non-message field"); + const upb_def *def = upb_fielddef_subdef(f); + lupb_def_pushwrapper(L, def, NULL); + return 1; +} + +static int lupb_fielddef_subdefname(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + if (!upb_fielddef_hassubdef(f)) + luaL_error(L, "Tried to get subdef name of non-message field"); + lua_pushstring(L, upb_fielddef_subdefname(f)); + return 1; +} + +static int lupb_fielddef_type(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushnumber(L, upb_fielddef_type(f)); + return 1; } static int lupb_fielddef_gc(lua_State *L) { - lupb_fielddef *lfielddef = lupb_fielddef_check(L, 1); - upb_fielddef_unref(lfielddef->field); + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_FIELDDEF); + upb_def_unref(r->def, r); + r->refcounted = NULL; return 0; } +static const struct luaL_Reg lupb_fielddef_m[] = { + LUPB_COMMON_DEF_METHODS + + {"default", lupb_fielddef_default}, + {"has_subdef", lupb_fielddef_hassubdef}, + {"label", lupb_fielddef_label}, + {"msgdef", lupb_fielddef_msgdef}, + {"name", lupb_def_fullname}, // name() is just an alias for fullname() + {"number", lupb_fielddef_number}, + {"subdef", lupb_fielddef_subdef}, + {"subdef_name", lupb_fielddef_subdefname}, + {"type", lupb_fielddef_type}, + + {"set_default", lupb_fielddef_setdefault}, + {"set_label", lupb_fielddef_setlabel}, + {"set_name", lupb_def_setfullname}, // name() is just an alias for fullname() + {"set_number", lupb_fielddef_setnumber}, + {"set_subdef", lupb_fielddef_setsubdef}, + {"set_subdef_name", lupb_fielddef_setsubdefname}, + {"set_type", lupb_fielddef_settype}, + + // Internal-only. + {"_selector_base", lupb_fielddef_selectorbase}, + + {NULL, NULL} +}; + static const struct luaL_Reg lupb_fielddef_mm[] = { {"__gc", lupb_fielddef_gc}, - {"__index", lupb_fielddef_index}, - {"__newindex", lupb_fielddef_newindex}, {NULL, NULL} }; /* lupb_msgdef ****************************************************************/ -static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) { - lupb_def *ldef = luaL_checkudata(L, narg, "upb.msgdef"); - luaL_argcheck(L, ldef != NULL, narg, "upb msgdef expected"); - return upb_downcast_msgdef(ldef->def); +const upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_MSGDEF); + if (!r) luaL_typerror(L, narg, LUPB_MSGDEF); + if (!r->refcounted) luaL_error(L, "called into dead msgdef"); + return upb_downcast_msgdef(r->def); } -static int lupb_msgdef_gc(lua_State *L) { - lupb_def *ldef = luaL_checkudata(L, 1, "upb.msgdef"); - upb_def_unref(ldef->def); - return 0; +static upb_msgdef *lupb_msgdef_checkmutable(lua_State *L, int narg) { + const upb_msgdef *m = lupb_msgdef_check(L, narg); + if (upb_msgdef_isfrozen(m)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_msgdef*)m; } -static int lupb_msgdef_call(lua_State *L) { - upb_msgdef *md = lupb_msgdef_check(L, 1); - lupb_msg_pushnew(L, md); - return 1; +static int lupb_msgdef_gc(lua_State *L) { + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_MSGDEF); + upb_def_unref(r->def, r); + r->refcounted = NULL; + return 0; } static int lupb_msgdef_new(lua_State *L) { - upb_msgdef *md = upb_msgdef_new(); - lupb_cache_create(L, md, "upb.msgdef"); + int narg = lua_gettop(L); + upb_msgdef *md = upb_msgdef_new(&md); + lupb_def_pushnewrapper(L, upb_upcast(md), &md); - if (lua_gettop(L) == 0) return 1; + if (narg == 0) return 1; // User can specify initialization values like so: - // upb.MessageDef{fqname="MyMessage", extstart=8000, fields={...}} + // upb.MessageDef{full_name="MyMessage", extstart=8000, fields={...}} luaL_checktype(L, 1, LUA_TTABLE); - // Iterate over table. - lua_pushnil(L); // first key - while (lua_next(L, 1)) { + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { luaL_checktype(L, -2, LUA_TSTRING); const char *key = lua_tostring(L, -2); - if (streql(key, "fqname")) { // fqname="MyMessage" + if (streql(key, "full_name")) { // full_name="MyMessage" const char *fqname = lua_tostring(L, -1); - if (!fqname || !upb_def_setfqname(UPB_UPCAST(md), fqname)) - luaL_error(L, "Invalid fqname"); + if (!fqname || !upb_def_setfullname(upb_upcast(md), fqname)) + luaL_error(L, "Invalid full_name"); } else if (streql(key, "fields")) { // fields={...} // Iterate over the list of fields. - lua_pushnil(L); - luaL_checktype(L, -2, LUA_TTABLE); - while (lua_next(L, -2)) { - lupb_fielddef *f = lupb_fielddef_check(L, -1); - if (!upb_msgdef_addfield(md, f->field)) { + luaL_checktype(L, -1, LUA_TTABLE); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, -1); + if (!upb_msgdef_addfield(md, f, NULL)) { // TODO: more specific error. luaL_error(L, "Could not add field."); } - lua_pop(L, 1); } } else { // TODO: extrange= luaL_error(L, "Unknown initializer key '%s'", key); } + } + return 1; +} + +static int lupb_msgdef_add(lua_State *L) { + upb_msgdef *m = lupb_msgdef_checkmutable(L, 1); + luaL_checktype(L, 2, LUA_TTABLE); + int n = lua_rawlen(L, 2); + // TODO: add upb interface that lets us avoid this malloc/free. + upb_fielddef **fields = malloc(n * sizeof(upb_fielddef*)); + for (int i = 0; i < n; i++) { + lua_rawgeti(L, -1, i + 1); + fields[i] = lupb_fielddef_checkmutable(L, -1); lua_pop(L, 1); } + + bool success = upb_msgdef_addfields(m, fields, n, NULL); + free(fields); + if (!success) luaL_error(L, "fields could not be added"); + return 0; +} + +static int lupb_msgdef_len(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushinteger(L, upb_msgdef_numfields(m)); return 1; } -static int lupb_msgdef_fqname(lua_State *L) { - upb_msgdef *m = lupb_msgdef_check(L, 1); - lua_pushstring(L, m->base.fqname); +static int lupb_msgdef_selectorcount(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushinteger(L, m->selector_count); return 1; } -static int lupb_msgdef_fieldbyname(lua_State *L) { - upb_msgdef *m = lupb_msgdef_check(L, 1); - upb_fielddef *f = upb_msgdef_ntof(m, luaL_checkstring(L, 2)); - if (f) { - lupb_fielddef_getorcreate(L, f); +static int lupb_msgdef_field(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + int type = lua_type(L, 2); + const upb_fielddef *f; + if (type == LUA_TNUMBER) { + f = upb_msgdef_itof(m, lua_tointeger(L, 2)); + } else if (type == LUA_TSTRING) { + f = upb_msgdef_ntof(m, lua_tostring(L, 2)); } else { - lua_pushnil(L); + const char *msg = lua_pushfstring(L, "number or string expected, got %s", + luaL_typename(L, 2)); + return luaL_argerror(L, 2, msg); } + + lupb_def_pushwrapper(L, upb_upcast(f), NULL); return 1; } -static int lupb_msgdef_fieldbynum(lua_State *L) { - upb_msgdef *m = lupb_msgdef_check(L, 1); - int num = luaL_checkint(L, 2); - upb_fielddef *f = upb_msgdef_itof(m, num); - if (f) { - lupb_fielddef_getorcreate(L, f); - } else { - lua_pushnil(L); - } +static int lupb_msgiter_next(lua_State *L) { + upb_msg_iter *i = lua_touserdata(L, lua_upvalueindex(1)); + if (upb_msg_done(i)) return 0; + lupb_def_pushwrapper(L, upb_upcast(upb_msg_iter_field(i)), NULL); + upb_msg_next(i); + return 1; +} + +static int lupb_msgdef_fields(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + upb_msg_iter *i = lua_newuserdata(L, sizeof(upb_msg_iter)); + upb_msg_begin(i, m); + lua_pushcclosure(L, &lupb_msgiter_next, 1); return 1; } static const struct luaL_Reg lupb_msgdef_mm[] = { - {"__call", lupb_msgdef_call}, {"__gc", lupb_msgdef_gc}, + {"__len", lupb_msgdef_len}, {NULL, NULL} }; static const struct luaL_Reg lupb_msgdef_m[] = { - {"fieldbyname", lupb_msgdef_fieldbyname}, - {"fieldbynum", lupb_msgdef_fieldbynum}, - {"fqname", lupb_msgdef_fqname}, + LUPB_COMMON_DEF_METHODS + {"add", lupb_msgdef_add}, + {"field", lupb_msgdef_field}, + {"fields", lupb_msgdef_fields}, + + // Internal-only. + {"_selector_count", lupb_msgdef_selectorcount}, + {NULL, NULL} }; /* lupb_enumdef ***************************************************************/ -static upb_enumdef *lupb_enumdef_check(lua_State *L, int narg) { - lupb_def *ldef = luaL_checkudata(L, narg, "upb.enumdef"); - return upb_downcast_enumdef(ldef->def); +const upb_enumdef *lupb_enumdef_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_ENUMDEF); + if (!r) luaL_typerror(L, narg, LUPB_ENUMDEF); + if (!r->refcounted) luaL_error(L, "called into dead enumdef"); + return upb_downcast_enumdef(r->def); +} + +static upb_enumdef *lupb_enumdef_checkmutable(lua_State *L, int narg) { + const upb_enumdef *f = lupb_enumdef_check(L, narg); + if (upb_enumdef_isfrozen(f)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_enumdef*)f; } static int lupb_enumdef_gc(lua_State *L) { - upb_enumdef *e = lupb_enumdef_check(L, 1); - upb_def_unref(UPB_UPCAST(e)); + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_ENUMDEF); + upb_def_unref(r->def, r); + r->refcounted = NULL; return 0; } -static int lupb_enumdef_name(lua_State *L) { - upb_enumdef *e = lupb_enumdef_check(L, 1); - lua_pushstring(L, e->base.fqname); +static int lupb_enumdef_new(lua_State *L) { + int narg = lua_gettop(L); + upb_enumdef *e = upb_enumdef_new(&e); + lupb_def_pushnewrapper(L, upb_upcast(e), &e); + + if (narg == 0) return 1; + + // User can specify initialization values like so: + // upb.EnumDef{full_name="MyEnum", + // values={ + // {"FOO_VALUE_1", 1}, + // {"FOO_VALUE_2", 2} + // } + // } + luaL_checktype(L, 1, LUA_TTABLE); + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); + const char *key = lua_tostring(L, -2); + if (streql(key, "values")) { + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + lua_rawgeti(L, -1, 1); + luaL_checktype(L, -1, LUA_TSTRING); + const char *name = lua_tostring(L, -1); + lua_rawgeti(L, -2, 2); + int32_t num = lupb_checkint32(L, -1, "value"); + upb_status status = UPB_STATUS_INIT; + upb_enumdef_addval(e, name, num, &status); + lupb_checkstatus(L, &status); + lua_pop(L, 2); // The key/val we got from lua_rawgeti() + } + } else if (streql(key, "full_name")) { + const char *fullname = lua_tostring(L, -1); + if (!fullname || !upb_def_setfullname(upb_upcast(e), fullname)) + luaL_error(L, "Invalid full_name"); + } else { + luaL_error(L, "Unknown initializer key '%s'", key); + } + } + return 1; +} + +static int lupb_enumdef_add(lua_State *L) { + upb_enumdef *e = lupb_enumdef_checkmutable(L, 1); + const char *name = lupb_checkname(L, 2); + int32_t num = lupb_checkint32(L, 3, "value"); + upb_status status = UPB_STATUS_INIT; + upb_enumdef_addval(e, name, num, &status); + lupb_checkstatus(L, &status); + return 0; +} + +static int lupb_enumdef_len(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + lua_pushinteger(L, upb_enumdef_numvals(e)); + return 1; +} + +static int lupb_enumdef_value(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + int type = lua_type(L, 2); + if (type == LUA_TNUMBER) { + // Pushes "nil" for a NULL pointer. + lua_pushstring(L, upb_enumdef_iton(e, lupb_checkint32(L, 2, "value"))); + } else if (type == LUA_TSTRING) { + int32_t num; + if (upb_enumdef_ntoi(e, lua_tostring(L, 2), &num)) { + lua_pushnumber(L, num); + } else { + lua_pushnil(L); + } + } else { + const char *msg = lua_pushfstring(L, "number or string expected, got %s", + luaL_typename(L, 2)); + return luaL_argerror(L, 2, msg); + } + return 1; +} + +static int lupb_enumiter_next(lua_State *L) { + upb_enum_iter *i = lua_touserdata(L, lua_upvalueindex(1)); + if (upb_enum_done(i)) return 0; + lua_pushstring(L, upb_enum_iter_name(i)); + lua_pushnumber(L, upb_enum_iter_number(i)); + upb_enum_next(i); + return 2; +} + +static int lupb_enumdef_values(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + upb_enum_iter *i = lua_newuserdata(L, sizeof(upb_enum_iter)); + upb_enum_begin(i, e); + lua_pushcclosure(L, &lupb_enumiter_next, 1); return 1; } static const struct luaL_Reg lupb_enumdef_mm[] = { {"__gc", lupb_enumdef_gc}, + {"__len", lupb_enumdef_len}, {NULL, NULL} }; static const struct luaL_Reg lupb_enumdef_m[] = { - {"name", lupb_enumdef_name}, + LUPB_COMMON_DEF_METHODS + {"add", lupb_enumdef_add}, + {"value", lupb_enumdef_value}, + {"values", lupb_enumdef_values}, {NULL, NULL} }; /* lupb_symtab ****************************************************************/ -typedef struct { - upb_symtab *symtab; -} lupb_symtab; - -static upb_accessor_vtbl *lupb_accessor(upb_fielddef *f); - // Inherits a ref on the symtab. // Checks that narg is a proper lupb_symtab object. If it is, leaves its // metatable on the stack for cache lookups/updates. -lupb_symtab *lupb_symtab_check(lua_State *L, int narg) { - return luaL_checkudata(L, narg, "upb.symtab"); +upb_symtab *lupb_symtab_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_SYMTAB); + if (!r) luaL_typerror(L, narg, LUPB_SYMTAB); + if (!r->refcounted) luaL_error(L, "called into dead symtab"); + return r->symtab; } // narg is a lua table containing a list of defs to add. @@ -509,93 +867,91 @@ void lupb_symtab_doadd(lua_State *L, upb_symtab *s, int narg) { // Iterate over table twice. First iteration to count entries and // check constraints. int n = 0; - lua_pushnil(L); // first key - while (lua_next(L, narg)) { + for (lua_pushnil(L); lua_next(L, narg); lua_pop(L, 1)) { lupb_def_check(L, -1); ++n; - lua_pop(L, 1); } // Second iteration to build deflist and layout. upb_def **defs = malloc(n * sizeof(*defs)); n = 0; - lua_pushnil(L); // first key - while (lua_next(L, 1)) { - upb_def *def = lupb_def_check(L, -1)->def; + for (lua_pushnil(L); lua_next(L, narg); lua_pop(L, 1)) { + upb_def *def = lupb_def_checkmutable(L, -1); defs[n++] = def; - upb_msgdef *md = upb_dyncast_msgdef(def); - if (md) { - upb_msg_iter i; - for(i = upb_msg_begin(md); !upb_msg_done(i); i = upb_msg_next(md, i)) { - upb_fielddef *f = upb_msg_iter_field(i); - upb_fielddef_setaccessor(f, lupb_accessor(f)); - } - upb_msgdef_layout(md); - } - lua_pop(L, 1); } upb_status status = UPB_STATUS_INIT; - upb_symtab_add(s, defs, n, &status); + upb_symtab_add(s, defs, n, NULL, &status); free(defs); lupb_checkstatus(L, &status); } static int lupb_symtab_new(lua_State *L) { - upb_symtab *s = upb_symtab_new(); - lupb_cache_create(L, s, "upb.symtab"); - if (lua_gettop(L) == 0) return 1; - lupb_symtab_doadd(L, s, 1); + int narg = lua_gettop(L); + upb_symtab *s = upb_symtab_new(&s); + lupb_refcounted_pushnewrapper(L, upb_upcast(s), LUPB_SYMTAB, &s); + if (narg > 0) lupb_symtab_doadd(L, s, 1); return 1; } static int lupb_symtab_add(lua_State *L) { - lupb_symtab *s = lupb_symtab_check(L, 1); - lupb_symtab_doadd(L, s->symtab, 2); + lupb_symtab_doadd(L, lupb_symtab_check(L, 1), 2); return 0; } static int lupb_symtab_gc(lua_State *L) { - lupb_symtab *s = lupb_symtab_check(L, 1); - upb_symtab_unref(s->symtab); + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_SYMTAB); + upb_symtab_unref(r->symtab, r); + r->refcounted = NULL; return 0; } static int lupb_symtab_lookup(lua_State *L) { - lupb_symtab *s = lupb_symtab_check(L, 1); + upb_symtab *s = lupb_symtab_check(L, 1); for (int i = 2; i <= lua_gettop(L); i++) { - const upb_def *def = upb_symtab_lookup(s->symtab, luaL_checkstring(L, i)); - if (def) { - lupb_def_getorcreate(L, def, true); - } else { - lua_pushnil(L); - } + const upb_def *def = + upb_symtab_lookup(s, luaL_checkstring(L, i), &def); + lupb_def_pushwrapper(L, def, &def); lua_replace(L, i); } return lua_gettop(L) - 1; } static int lupb_symtab_getdefs(lua_State *L) { - lupb_symtab *s = lupb_symtab_check(L, 1); + upb_symtab *s = lupb_symtab_check(L, 1); upb_deftype_t type = luaL_checkint(L, 2); int count; - const upb_def **defs = upb_symtab_getdefs(s->symtab, &count, type); + const upb_def **defs = upb_symtab_getdefs(s, type, &defs, &count); // Create the table in which we will return the defs. lua_createtable(L, count, 0); for (int i = 0; i < count; i++) { const upb_def *def = defs[i]; - lupb_def_getorcreate(L, def, true); + lupb_def_pushwrapper(L, def, &defs); lua_rawseti(L, -2, i + 1); } free(defs); return 1; } +// This is a *temporary* API that will be removed once pending refactorings are +// complete (it does not belong here in core because it depends on both +// the descriptor.proto schema and the protobuf binary format. +static int lupb_symtab_load_descriptor(lua_State *L) { + size_t len; + upb_symtab *s = lupb_symtab_check(L, 1); + const char *str = luaL_checklstring(L, 2, &len); + upb_status status = UPB_STATUS_INIT; + upb_load_descriptor_into_symtab(s, str, len, &status); + lupb_checkstatus(L, &status); + return 0; +} + static const struct luaL_Reg lupb_symtab_m[] = { {"add", lupb_symtab_add}, {"getdefs", lupb_symtab_getdefs}, {"lookup", lupb_symtab_lookup}, + {"load_descriptor", lupb_symtab_load_descriptor}, {NULL, NULL} }; @@ -605,343 +961,28 @@ static const struct luaL_Reg lupb_symtab_mm[] = { }; -/* lupb_msg********************************************************************/ - -// Messages are userdata. Primitive values (numbers and bools, and their -// hasbits) are stored right in the userdata. Other values are stored using -// integer entries in the environment table and no hasbits are used (since -// "nil" in the environment table can indicate "not present"). -// -// The environment table looks like: -// {msgdef, } - -// Must pass a upb_fielddef as the pointer. -static void lupb_array_pushnew(lua_State *L, const void *f); - -static void *lupb_msg_check(lua_State *L, int narg, upb_msgdef **md) { - void *msg = luaL_checkudata(L, narg, "upb.msg"); - luaL_argcheck(L, msg != NULL, narg, "msg expected"); - // If going all the way to the environment table for the msgdef is an - // efficiency issue, we could put the pointer right in the userdata. - lua_getfenv(L, narg); - lua_rawgeti(L, -1, 1); - // Shouldn't have to check msgdef userdata validity, environment table can't - // be accessed from Lua. - lupb_def *lmd = lua_touserdata(L, -1); - *md = upb_downcast_msgdef(lmd->def); - return msg; -} - -static void lupb_msg_pushnew(lua_State *L, const void *md) { - void *msg = lua_newuserdata(L, upb_msgdef_size(md)); - luaL_getmetatable(L, "upb.msg"); - assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. - lua_setmetatable(L, -2); - upb_msg_clear(msg, md); - lua_getfenv(L, -1); - lupb_cache_getorcreate(L, (void*)md, "upb.msgdef"); - lua_rawseti(L, -2, 1); - lua_pop(L, 1); // Pop the fenv. -} - -static int lupb_msg_new(lua_State *L) { - upb_msgdef *md = lupb_msgdef_check(L, 1); - lupb_msg_pushnew(L, md); - return 1; -} - -static int lupb_msg_index(lua_State *L) { - upb_msgdef *md; - void *m = lupb_msg_check(L, 1, &md); - upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2)); - if (!f) luaL_argerror(L, 2, "not a field name"); - if (upb_isprimitivetype(upb_fielddef_type(f))) { - upb_value v = upb_msg_has(m, f) ? upb_msg_get(m, f) : upb_fielddef_default(f); - lupb_pushvalue(L, v, f); - } else { - lua_getfenv(L, 1); - lua_rawgeti(L, -1, f->offset); - if (lua_isnil(L, -1)) { - // Need to lazily create array, string, or submessage. - if (upb_isseq(f)) { - lupb_array_pushnew(L, f); - } else if (upb_isstring(f)) { - // TODO: (need to figure out default string ownership). - } else if (upb_issubmsg(f)) { - lupb_msg_pushnew(L, upb_downcast_msgdef(upb_fielddef_subdef(f))); - } else { - luaL_error(L, "internal error"); - } - lua_rawseti(L, -2, f->offset); - } - } - return 1; -} - -static int lupb_msg_newindex(lua_State *L) { - upb_msgdef *md; - void *m = lupb_msg_check(L, 1, &md); - upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2)); - if (!f) luaL_error(L, "not a field name"); - if (upb_isprimitivetype(upb_fielddef_type(f))) { - if (lua_isnil(L, 3)) - upb_msg_clearbit(m, f); - else - upb_msg_set(m, f, lupb_getvalue(L, 3, f, NULL)); - } else { - if (!lua_isnil(L, 3)) lupb_typecheck(L, 3, f); - lua_getfenv(L, 1); - lua_pushvalue(L, 3); - lua_rawseti(L, -1, f->offset); - } - return 0; -} - -static const struct luaL_Reg lupb_msg_mm[] = { - {"__index", lupb_msg_index}, - {"__newindex", lupb_msg_newindex}, - {NULL, NULL} -}; - -// Functions that operate on msgdefs but do not live in the msgdef namespace. -static int lupb_clear(lua_State *L) { - upb_msgdef *md; - void *m = lupb_msg_check(L, 1, &md); - upb_msg_clear(m, md); - return 0; -} - -static int lupb_has(lua_State *L) { - upb_msgdef *md; - void *m = lupb_msg_check(L, 1, &md); - upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2)); - if (!f) luaL_argerror(L, 2, "not a field name"); - lua_pushboolean(L, upb_msg_has(m, f)); - return 1; -} - -static int lupb_msgdef(lua_State *L) { - upb_msgdef *md; - lupb_msg_check(L, 1, &md); - lupb_def_getorcreate(L, UPB_UPCAST(md), false); - return 1; -} +/* lupb toplevel **************************************************************/ -// Accessors for arrays, strings, and submessages need access to the current -// userdata's environment table, which can only be stored in Lua space. -// Options for storing it are: -// -// - put the env tables for all messages and arrays in the registry, keyed by -// userdata pointer (light userdata), or by a reference using luaL_ref(). -// Then we can just let upb's parse stack track the stack of env tables. -// Easy but requires all messages and arrays to be in the registry, which -// seems too heavyweight. -// -// - store the stack of env tables in the Lua stack. Convenient, but requires -// special code to handle resumable decoders. -// -// There is also the question of how to obtain the lua_State* pointer. -// The main options for this are: -// -// - make our closure point to a struct: -// struct { void *msg; lua_State *L; } -// But then we can't use standard accessors, which expect the closure -// to point to the data itself. Using the standard accessors for -// primitive values is both a simplicity and a performance win. -// -// - store a lua_State* pointer inside each userdata. Convenient and -// efficient, but makes every message sizeof(void*) larger. -// Currently we take this route. -// -// - use thread-local storage. Convenient and efficient, but not portable. - -typedef void createfunc_t(lua_State *L, const void *param); - -static upb_sflow_t lupb_msg_start(void *m, const upb_fielddef *f, bool array, - createfunc_t *pushnew, const void *param) { - lua_State *L = *(lua_State**)m; - int offset = array ? lua_rawlen(L, -1) : f->offset; - if (!lua_checkstack(L, 3)) luaL_error(L, "stack full"); - lua_rawgeti(L, -1, offset); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - pushnew(L, param); - lua_pushvalue(L, -1); - lua_rawseti(L, -3, offset); +static int lupb_def_freeze(lua_State *L) { + int n = lua_gettop(L); + upb_def **defs = malloc(n * sizeof(upb_def*)); + for (int i = 0; i < n; i++) { + // Could allow an array of defs here also. + defs[i] = lupb_def_checkmutable(L, i + 1); } - void *subval = lua_touserdata(L, -1); - lua_getfenv(L, -1); - lua_replace(L, -2); // Replace subval userdata with fenv. - return UPB_CONTINUE_WITH(subval); -} - -static upb_flow_t lupb_msg_string(void *m, upb_value fval, upb_value val, - bool array) { - // Could add lazy materialization of strings here. - const upb_fielddef *f = upb_value_getfielddef(fval); - lua_State *L = *(lua_State**)m; - int offset = array ? lua_rawlen(L, -1) : f->offset; - if (!lua_checkstack(L, 1)) luaL_error(L, "stack full"); - lupb_pushstring(L, upb_value_getstrref(val)); - lua_rawseti(L, -2, offset); - return UPB_CONTINUE; -} - -static upb_sflow_t lupb_msg_startseq(void *m, upb_value fval) { - const upb_fielddef *f = upb_value_getfielddef(fval); - return lupb_msg_start(m, f, false, lupb_array_pushnew, f); -} - -static upb_sflow_t lupb_msg_startsubmsg(void *m, upb_value fval) { - const upb_fielddef *f = upb_value_getfielddef(fval); - return lupb_msg_start(m, f, false, lupb_msg_pushnew, upb_fielddef_subdef(f)); -} - -static upb_sflow_t lupb_msg_startsubmsg_r(void *a, upb_value fval) { - const upb_fielddef *f = upb_value_getfielddef(fval); - return lupb_msg_start(a, f, true, lupb_msg_pushnew, upb_fielddef_subdef(f)); -} - -static upb_flow_t lupb_msg_stringval(void *m, upb_value fval, upb_value val) { - return lupb_msg_string(m, fval, val, false); -} - -static upb_flow_t lupb_msg_stringval_r(void *a, upb_value fval, upb_value val) { - return lupb_msg_string(a, fval, val, true); -} - -#define STDMSG(type, size) static upb_accessor_vtbl vtbl = { \ - &lupb_msg_startsubmsg, \ - &upb_stdmsg_set ## type, \ - &lupb_msg_startseq, \ - &lupb_msg_startsubmsg_r, \ - &upb_stdmsg_set ## type ## _r, \ - &upb_stdmsg_has, \ - &upb_stdmsg_getptr, \ - &upb_stdmsg_get ## type, \ - &upb_stdmsg_seqbegin, \ - &upb_stdmsg_ ## size ## byte_seqnext, \ - &upb_stdmsg_seqget ## type}; - -#define RETURN_STDMSG(type, size) { STDMSG(type, size); return &vtbl; } - -static upb_accessor_vtbl *lupb_accessor(upb_fielddef *f) { - switch (f->type) { - case UPB_TYPE(DOUBLE): RETURN_STDMSG(double, 8) - case UPB_TYPE(FLOAT): RETURN_STDMSG(float, 4) - case UPB_TYPE(UINT64): - case UPB_TYPE(FIXED64): RETURN_STDMSG(uint64, 8) - case UPB_TYPE(INT64): - case UPB_TYPE(SFIXED64): - case UPB_TYPE(SINT64): RETURN_STDMSG(int64, 8) - case UPB_TYPE(INT32): - case UPB_TYPE(SINT32): - case UPB_TYPE(ENUM): - case UPB_TYPE(SFIXED32): RETURN_STDMSG(int32, 4) - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): RETURN_STDMSG(uint32, 4) - case UPB_TYPE(BOOL): { STDMSG(bool, 1); return &vtbl; } - case UPB_TYPE(GROUP): - case UPB_TYPE(MESSAGE): RETURN_STDMSG(ptr, 8) // TODO: 32-bit - case UPB_TYPE(STRING): - case UPB_TYPE(BYTES): { - STDMSG(ptr, 8); - vtbl.set = &lupb_msg_stringval; - vtbl.append = &lupb_msg_stringval_r; - return &vtbl; - } - } - return NULL; -} - - -/* lupb_array ****************************************************************/ - -// Array: we store all elements in the environment table. Could optimize by -// storing primitive arrays in our own memory; this would be significantly more -// space efficient. Lua array elements are 16 bytes each; our own array would -// be 1/4 the space for 32-bit integers, or 1/16 the space for booleans. -// -// The first element of the environment table stores our type (which will be -// either an integer from upb.TYPE_* or a upb.msgdef), the remaining elements -// store the elements. We always keep all elements contiguous so we can use -// lua_objlen()/lua_rawlen() (for Lua 5.1/5.2 respectively) to report its len). - -// narg is offset of environment table. -static size_t lupb_array_getlen(lua_State *L, int narg) { - return lua_rawlen(L, narg) - 1; -} - -static void lupb_array_check(lua_State *L, int narg) { - if (!luaL_checkudata(L, narg, "upb.array")) - luaL_typerror(L, narg, "upb array"); -} - -static void lupb_array_pushnew(lua_State *L, const void *f) { - (void)L; - (void)f; -} - -static int lupb_array_new(lua_State *L) { - (void)L; - return 0; -} - -static int lupb_array_len(lua_State *L) { - lupb_array_check(L, 1); - lua_getfenv(L, 1); - lua_pushnumber(L, lupb_array_getlen(L, -1)); - return 1; -} - -static int lupb_array_index(lua_State *L) { - assert(lua_gettop(L) == 2); // __index should always be called with 2 args. - lupb_array_check(L, 1); - lua_Number num = luaL_checknumber(L, 2); - if (!lupb_isint(num)) luaL_typerror(L, 2, "integer"); - - lua_getfenv(L, 1); - size_t len = lupb_array_getlen(L, -1); - if (num < 1 || num > len) luaL_error(L, "array bounds check failed"); - lua_rawgeti(L, -1, num + 1); - return 1; -} - -static int lupb_array_newindex(lua_State *L) { - assert(lua_gettop(L) == 3); // __newindex should always be called with 3 args. - lupb_array_check(L, 1); - lua_Number num = luaL_checknumber(L, 2); - if (rint(num) != num) luaL_typerror(L, 2, "integer"); - - lua_getfenv(L, 1); - size_t len = lupb_array_getlen(L, -1); - // We only allow extending the index one beyond the end. - if (num < 1 || num > len + 1) luaL_error(L, "array bounds check failed"); - lua_pushvalue(L, 3); - lua_rawseti(L, -2, num); + upb_status s = UPB_STATUS_INIT; + upb_def_freeze(defs, n, &s); + free(defs); + lupb_checkstatus(L, &s); return 0; } -static const struct luaL_Reg lupb_array_mm[] = { - {"__len", lupb_array_len}, - {"__index", lupb_array_index}, - {"__newindex", lupb_array_newindex}, - {NULL, NULL} -}; - -/* lupb toplevel **************************************************************/ - static const struct luaL_Reg lupb_toplevel_m[] = { - {"SymbolTable", lupb_symtab_new}, - {"MessageDef", lupb_msgdef_new}, + {"EnumDef", lupb_enumdef_new}, {"FieldDef", lupb_fielddef_new}, - - {"Message", lupb_msg_new}, - {"Array", lupb_array_new}, - - {"clear", lupb_clear}, - {"msgdef", lupb_msgdef}, - {"has", lupb_has}, + {"MessageDef", lupb_msgdef_new}, + {"SymbolTable", lupb_symtab_new}, + {"freeze", lupb_def_freeze}, {NULL, NULL} }; @@ -950,14 +991,12 @@ static const struct luaL_Reg lupb_toplevel_m[] = { static void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m, const luaL_Reg *mm) { luaL_newmetatable(L, name); - luaL_register(L, NULL, mm); // Register all mm in the metatable. + lupb_setfuncs(L, mm); // Register all mm in the metatable. lua_createtable(L, 0, 0); - if (m) { - // Methods go in the mt's __index method. This implies that you can't - // implement __index and also set methods yourself. - luaL_register(L, NULL, m); - lua_setfield(L, -2, "__index"); - } + // Methods go in the mt's __index method. This implies that you can't + // implement __index. + lupb_setfuncs(L, m); + lua_setfield(L, -2, "__index"); lua_pop(L, 1); // The mt. } @@ -967,46 +1006,71 @@ static void lupb_setfieldi(lua_State *L, const char *field, int i) { } int luaopen_upb(lua_State *L) { - lupb_register_type(L, "upb.msgdef", lupb_msgdef_m, lupb_msgdef_mm); - lupb_register_type(L, "upb.enumdef", lupb_enumdef_m, lupb_enumdef_mm); - lupb_register_type(L, "upb.fielddef", NULL, lupb_fielddef_mm); - lupb_register_type(L, "upb.symtab", lupb_symtab_m, lupb_symtab_mm); - - lupb_register_type(L, "upb.msg", NULL, lupb_msg_mm); - lupb_register_type(L, "upb.array", NULL, lupb_msg_mm); + lupb_register_type(L, LUPB_MSGDEF, lupb_msgdef_m, lupb_msgdef_mm); + lupb_register_type(L, LUPB_ENUMDEF, lupb_enumdef_m, lupb_enumdef_mm); + lupb_register_type(L, LUPB_FIELDDEF, lupb_fielddef_m, lupb_fielddef_mm); + lupb_register_type(L, LUPB_SYMTAB, lupb_symtab_m, lupb_symtab_mm); // Create our object cache. - lua_createtable(L, 0, 0); + lua_newtable(L); lua_createtable(L, 0, 1); // Cache metatable. lua_pushstring(L, "v"); // Values are weak. lua_setfield(L, -2, "__mode"); - lua_setfield(L, LUA_REGISTRYINDEX, "upb.objcache"); + lua_setmetatable(L, -2); + lua_setfield(L, LUA_REGISTRYINDEX, LUPB_OBJCACHE); + + lupb_newlib(L, "upb", lupb_toplevel_m); + + // Define a couple functions as Lua source (kept here instead of a separate + // Lua file so that upb.so is self-contained) + const char *lua_source = + "return function(upb)\n" + " upb.build_defs = function(defs)\n" + " local symtab = upb.SymbolTable(defs)\n" + " return symtab:getdefs(upb.DEF_ANY)\n" + " end\n" + "end"; - luaL_register(L, "upb", lupb_toplevel_m); + if (luaL_dostring(L, lua_source) != 0) + lua_error(L); + + // Call the chunk that will define the extra functions on upb, passing our + // package dictionary as the argument. + lua_pushvalue(L, -2); + lua_call(L, 1, 0); // Register constants. lupb_setfieldi(L, "LABEL_OPTIONAL", UPB_LABEL(OPTIONAL)); lupb_setfieldi(L, "LABEL_REQUIRED", UPB_LABEL(REQUIRED)); lupb_setfieldi(L, "LABEL_REPEATED", UPB_LABEL(REPEATED)); - lupb_setfieldi(L, "TYPE_DOUBLE", UPB_TYPE(DOUBLE)); - lupb_setfieldi(L, "TYPE_FLOAT", UPB_TYPE(FLOAT)); - lupb_setfieldi(L, "TYPE_INT64", UPB_TYPE(INT64)); - lupb_setfieldi(L, "TYPE_UINT64", UPB_TYPE(UINT64)); - lupb_setfieldi(L, "TYPE_INT32", UPB_TYPE(INT32)); - lupb_setfieldi(L, "TYPE_FIXED64", UPB_TYPE(FIXED64)); - lupb_setfieldi(L, "TYPE_FIXED32", UPB_TYPE(FIXED32)); - lupb_setfieldi(L, "TYPE_BOOL", UPB_TYPE(BOOL)); - lupb_setfieldi(L, "TYPE_STRING", UPB_TYPE(STRING)); - lupb_setfieldi(L, "TYPE_GROUP", UPB_TYPE(GROUP)); - lupb_setfieldi(L, "TYPE_MESSAGE", UPB_TYPE(MESSAGE)); - lupb_setfieldi(L, "TYPE_BYTES", UPB_TYPE(BYTES)); - lupb_setfieldi(L, "TYPE_UINT32", UPB_TYPE(UINT32)); - lupb_setfieldi(L, "TYPE_ENUM", UPB_TYPE(ENUM)); - lupb_setfieldi(L, "TYPE_SFIXED32", UPB_TYPE(SFIXED32)); - lupb_setfieldi(L, "TYPE_SFIXED64", UPB_TYPE(SFIXED64)); - lupb_setfieldi(L, "TYPE_SINT32", UPB_TYPE(SINT32)); - lupb_setfieldi(L, "TYPE_SINT64", UPB_TYPE(SINT64)); + lupb_setfieldi(L, "TYPE_DOUBLE", UPB_TYPE(DOUBLE)); + lupb_setfieldi(L, "TYPE_FLOAT", UPB_TYPE(FLOAT)); + lupb_setfieldi(L, "TYPE_INT64", UPB_TYPE(INT64)); + lupb_setfieldi(L, "TYPE_UINT64", UPB_TYPE(UINT64)); + lupb_setfieldi(L, "TYPE_INT32", UPB_TYPE(INT32)); + lupb_setfieldi(L, "TYPE_FIXED64", UPB_TYPE(FIXED64)); + lupb_setfieldi(L, "TYPE_FIXED32", UPB_TYPE(FIXED32)); + lupb_setfieldi(L, "TYPE_BOOL", UPB_TYPE(BOOL)); + lupb_setfieldi(L, "TYPE_STRING", UPB_TYPE(STRING)); + lupb_setfieldi(L, "TYPE_GROUP", UPB_TYPE(GROUP)); + lupb_setfieldi(L, "TYPE_MESSAGE", UPB_TYPE(MESSAGE)); + lupb_setfieldi(L, "TYPE_BYTES", UPB_TYPE(BYTES)); + lupb_setfieldi(L, "TYPE_UINT32", UPB_TYPE(UINT32)); + lupb_setfieldi(L, "TYPE_ENUM", UPB_TYPE(ENUM)); + lupb_setfieldi(L, "TYPE_SFIXED32", UPB_TYPE(SFIXED32)); + lupb_setfieldi(L, "TYPE_SFIXED64", UPB_TYPE(SFIXED64)); + lupb_setfieldi(L, "TYPE_SINT32", UPB_TYPE(SINT32)); + lupb_setfieldi(L, "TYPE_SINT64", UPB_TYPE(SINT64)); + + lupb_setfieldi(L, "DEF_MSG", UPB_DEF_MSG); + lupb_setfieldi(L, "DEF_FIELD", UPB_DEF_FIELD); + lupb_setfieldi(L, "DEF_ENUM", UPB_DEF_ENUM); + lupb_setfieldi(L, "DEF_SERVICE", UPB_DEF_SERVICE); + lupb_setfieldi(L, "DEF_ANY", UPB_DEF_ANY); return 1; // Return package table. } + +// Alternate names so that the library can be loaded as upb5_1 etc. +int LUPB_OPENFUNC(upb)(lua_State *L) { return luaopen_upb(L); } diff --git a/bindings/lua/upb.h b/bindings/lua/upb.h new file mode 100644 index 0000000..e6b4f2f --- /dev/null +++ b/bindings/lua/upb.h @@ -0,0 +1,45 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman + * + * Shared definitions for upb Lua modules. + */ + +#ifndef UPB_LUA_UPB_H_ +#define UPB_LUA_UPB_H_ + +#include "upb/def.h" + +// Lua 5.1/5.2 compatibility code. +#if LUA_VERSION_NUM == 501 + +#define lua_rawlen lua_objlen +#define lupb_newlib(L, name, l) luaL_register(L, name, l) +#define lupb_setfuncs(L, l) luaL_register(L, NULL, l) +#define LUPB_OPENFUNC(mod) luaopen_ ## mod ## upb5_1 + +void *luaL_testudata(lua_State *L, int ud, const char *tname); + +#elif LUA_VERSION_NUM == 502 + +// Lua 5.2 modules are not expected to set a global variable, so "name" is +// unused. +#define lupb_newlib(L, name, l) luaL_newlib(L, l) +#define lupb_setfuncs(L, l) luaL_setfuncs(L, l, 0) +int luaL_typerror(lua_State *L, int narg, const char *tname); +#define LUPB_OPENFUNC(mod) luaopen_ ## mod ## upb5_2 + +#else +#error Only Lua 5.1 and 5.2 are supported +#endif + +const upb_msgdef *lupb_msgdef_check(lua_State *L, int narg); +const upb_enumdef *lupb_enumdef_check(lua_State *L, int narg); +const char *lupb_checkname(lua_State *L, int narg); +bool lupb_def_pushwrapper(lua_State *L, const upb_def *def, const void *owner); +void lupb_def_pushnewrapper(lua_State *L, const upb_def *def, + const void *owner); + +#endif // UPB_LUA_UPB_H_ -- cgit v1.2.3