summaryrefslogtreecommitdiff
path: root/cpp/rubygen/templates/structs.rb
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/rubygen/templates/structs.rb')
-rw-r--r--cpp/rubygen/templates/structs.rb345
1 files changed, 345 insertions, 0 deletions
diff --git a/cpp/rubygen/templates/structs.rb b/cpp/rubygen/templates/structs.rb
new file mode 100644
index 0000000000..972a0386b9
--- /dev/null
+++ b/cpp/rubygen/templates/structs.rb
@@ -0,0 +1,345 @@
+#!/usr/bin/env ruby
+# Usage: output_directory xml_spec_file [xml_spec_file...]
+#
+$: << '..'
+require 'cppgen'
+
+class StructGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ end
+
+ EncodingMap={
+ "octet"=>"Octet",
+ "short"=>"Short",
+ "long"=>"Long",
+ "longlong"=>"LongLong",
+ "longstr"=>"LongString",
+ "shortstr"=>"ShortString",
+ "timestamp"=>"LongLong",
+ "uuid"=>"ShortString",#FIXME
+ "table"=>"FieldTable",
+ "content"=>"Content",
+ "long-struct"=>"LongString"
+ }
+ SizeMap={
+ "octet"=>"1",
+ "short"=>"2",
+ "long"=>"4",
+ "longlong"=>"8",
+ "timestamp"=>"8"
+ }
+
+ ValueTypes=["octet", "short", "long", "longlong", "timestamp"]
+
+ def printable_form(f)
+ if (f.cpptype == "u_int8_t")
+ return "(int) " + f.cppname
+ else
+ return f.cppname
+ end
+ end
+
+ def generate_encode(f, combined)
+ if (f.field_type == "bit")
+ genl "uint8_t #{f.cppname}_bits = #{f.cppname};"
+ count = 0
+ combined.each { |c| genl "#{f.cppname}_bits |= #{c.cppname} << #{count += 1};" }
+ genl "buffer.putOctet(#{f.cppname}_bits);"
+ else
+ encoded = EncodingMap[f.field_type]
+ if (encoded)
+ genl "buffer.put#{encoded}(#{f.cppname});"
+ else
+ genl "#{f.cppname}.encode(buffer);"
+ end
+ end
+ end
+
+ def generate_decode(f, combined)
+ if (f.field_type == "bit")
+ genl "uint8_t #{f.cppname}_bits = buffer.getOctet();"
+ genl "#{f.cppname} = 1 & #{f.cppname}_bits;"
+ count = 0
+ combined.each { |c| genl "#{c.cppname} = (1 << #{count += 1}) & #{f.cppname}_bits;" }
+ else
+ encoded = EncodingMap[f.field_type]
+ if (encoded)
+ if (ValueTypes.include?(f.field_type))
+ genl "#{f.cppname} = buffer.get#{encoded}();"
+ else
+ genl "buffer.get#{encoded}(#{f.cppname});"
+ end
+ else
+ genl "#{f.cppname}.decode(buffer);"
+ end
+ end
+ end
+
+ def generate_size(f, combined)
+ if (f.field_type == "bit")
+ names = ([f] + combined).collect {|g| g.cppname}
+ genl "+ 1 //#{names.join(", ")}"
+ else
+ size = SizeMap[f.field_type]
+ if (size)
+ genl "+ #{size} //#{f.cppname}"
+ elsif (f.cpp_member_type == "SequenceNumberSet")
+ genl "+ #{f.cppname}.encodedSize()"
+ else
+ encoded = EncodingMap[f.field_type]
+ gen "+ 4 " if encoded == "LongString"
+ gen "+ 1 " if encoded == "ShortString"
+ genl "+ #{f.cppname}.size()"
+ end
+ end
+ end
+
+ def process_fields(s)
+ last = nil
+ count = 0
+ bits = []
+ s.fields.each {
+ |f| if (last and last.bit? and f.bit? and count < 7)
+ count += 1
+ bits << f
+ else
+ if (last and last.bit?)
+ yield last, bits
+ count = 0
+ bits = []
+ end
+ if (not f.bit?)
+ yield f
+ end
+ last = f
+ end
+ }
+ if (last and last.bit?)
+ yield last, bits
+ end
+ end
+
+ def methodbody_extra_defs(s)
+ gen <<EOS
+ using AMQMethodBody::accept;
+ void accept(MethodBodyConstVisitor& v) const { v.visit(*this); }
+
+ inline ClassId amqpClassId() const { return CLASS_ID; }
+ inline MethodId amqpMethodId() const { return METHOD_ID; }
+EOS
+ if (s.is_server_method?)
+ gen <<EOS
+ void invoke(AMQP_ServerOperations& target)
+ {
+ target.get#{s.amqp_parent.cppname}Handler()->#{s.cppname}
+ (
+EOS
+ if (s.amqp_parent.name == "message" && (s.name == "transfer" || s.name == "append"))
+ indent(4) { genl "*this" }
+ else
+ indent(4) { genl s.param_names.join(",\n") }
+ end
+
+ genl <<EOS
+ );
+ }
+
+ bool invoke(Invocable* target)
+ {
+ AMQP_ServerOperations::#{s.amqp_parent.cppname}Handler* ptr
+ = dynamic_cast<AMQP_ServerOperations::#{s.amqp_parent.cppname}Handler*>(target);
+ if (ptr) {
+ ptr->#{s.cppname}(
+EOS
+ if (s.amqp_parent.name == "message" && (s.name == "transfer" || s.name == "append"))
+ indent(5) { genl "*this" }
+ else
+ indent(5) { genl s.param_names.join(",\n") }
+ end
+
+ gen <<EOS
+ );
+ return true;
+ } else {
+ return false;
+ }
+ }
+EOS
+ end
+ end
+
+ def define_constructor(name, s)
+ if (s.fields.size > 0)
+ genl "#{name}("
+ if (s.kind_of? AmqpMethod)
+ indent {gen "ProtocolVersion, "}
+ end
+ indent { gen s.fields.collect { |f| "#{f.cpptype} _#{f.cppname}" }.join(",\n") }
+ gen ")"
+ genl ": " if s.fields.size > 0
+ indent { gen s.fields.collect { |f| " #{f.cppname}(_#{f.cppname})" }.join(",\n") }
+ genl " {}"
+ end
+ if (s.kind_of? AmqpMethod)
+ genl "#{name}(ProtocolVersion=ProtocolVersion()) {}"
+ end
+ end
+
+ def define_accessors(f)
+ genl "void set#{f.name.caps}(#{f.cpptype} _#{f.cppname}) { #{f.cppname} = _#{f.cppname}; }"
+ genl "#{f.cpptype} get#{f.name.caps}() const { return #{f.cppname}; }"
+ end
+
+ def define_struct(s)
+ classname = s.cppname
+ inheritance = ""
+ if (s.kind_of? AmqpMethod)
+ classname = s.body_name
+ inheritance = ": public AMQMethodBody"
+ end
+
+ h_file("qpid/framing/#{classname}.h") {
+ if (s.kind_of? AmqpMethod)
+ gen <<EOS
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/MethodBodyConstVisitor.h"
+EOS
+ end
+
+ #need to include any nested struct definitions
+ s.fields.select {|f| f.defined_as_struct }.map {|f| include f.name.caps}
+
+ gen <<EOS
+
+#include <ostream>
+#include "qpid/framing/amqp_types_full.h"
+
+namespace qpid {
+namespace framing {
+
+class #{classname} #{inheritance} {
+EOS
+ indent { s.fields.each { |f| genl "#{f.cpp_member_type} #{f.cppname};" } }
+ genl "public:"
+ if (s.kind_of? AmqpMethod)
+ indent { genl "static const ClassId CLASS_ID = #{s.amqp_parent.index};" }
+ indent { genl "static const MethodId METHOD_ID = #{s.index};" }
+ end
+
+ if (s.kind_of? AmqpStruct)
+ if (s.type)
+ if (s.result?)
+ #as result structs have types that are only unique to the
+ #class, they have a class dependent qualifier added to them
+ #(this is inline with current python code but a formal
+ #solution is expected from the WG
+ indent { genl "static const uint16_t TYPE = #{s.type} + #{s.amqp_parent.amqp_parent.index} * 256;" }
+ else
+ indent { genl "static const uint16_t TYPE = #{s.type};" }
+ end
+ end
+ end
+
+ indent {
+ define_constructor(classname, s)
+ genl ""
+ s.fields.each { |f| define_accessors(f) }
+ }
+ if (s.kind_of? AmqpMethod)
+ methodbody_extra_defs(s)
+ end
+ if (s.kind_of? AmqpStruct)
+ indent {genl "friend std::ostream& operator<<(std::ostream&, const #{classname}&);" }
+ end
+
+ gen <<EOS
+ void encode(Buffer&) const;
+ void decode(Buffer&, uint32_t=0);
+ uint32_t size() const;
+ void print(std::ostream& out) const;
+}; /* class #{classname} */
+
+}}
+EOS
+ }
+ cpp_file("qpid/framing/#{classname}.cpp") {
+ if (s.fields.size > 0)
+ buffer = "buffer"
+ else
+ buffer = "/*buffer*/"
+ end
+ gen <<EOS
+#include "#{classname}.h"
+
+using namespace qpid::framing;
+
+void #{classname}::encode(Buffer& #{buffer}) const
+{
+EOS
+ indent { process_fields(s) { |f, combined| generate_encode(f, combined) } }
+ gen <<EOS
+}
+
+void #{classname}::decode(Buffer& #{buffer}, uint32_t /*size*/)
+{
+EOS
+ indent { process_fields(s) { |f, combined| generate_decode(f, combined) } }
+ gen <<EOS
+}
+
+uint32_t #{classname}::size() const
+{
+ return 0
+EOS
+ indent { process_fields(s) { |f, combined| generate_size(f, combined) } }
+ gen <<EOS
+ ;
+}
+
+void #{classname}::print(std::ostream& out) const
+{
+ out << "#{classname}: ";
+EOS
+ copy = Array.new(s.fields)
+ f = copy.shift
+
+ indent {
+ genl "out << \"#{f.name}=\" << #{printable_form(f)};" if f
+ copy.each { |f| genl "out << \"; #{f.name}=\" << #{printable_form(f)};" }
+ }
+ gen <<EOS
+}
+EOS
+
+ if (s.kind_of? AmqpStruct)
+ gen <<EOS
+namespace qpid{
+namespace framing{
+
+ std::ostream& operator<<(std::ostream& out, const #{classname}& s)
+ {
+ s.print(out);
+ return out;
+ }
+
+}
+}
+EOS
+ end
+
+}
+ end
+
+ def generate()
+ @amqp.amqp_structs.each { |s| define_struct(s) }
+ @amqp.amqp_methods.each { |m| define_struct(m) }
+ #generate a single include file containing the list of structs for convenience
+ h_file("qpid/framing/amqp_structs.h") { @amqp.amqp_structs.each { |s| genl "#include \"#{s.cppname}.h\"" } }
+ end
+end
+
+StructGen.new(ARGV[0], Amqp).generate()
+