From 0dacbb87dcd294da9a61c398910d9bed95006287 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 10 Nov 2023 12:26:59 -0800 Subject: [PATCH] [Yunq] Add repeated field parsing and serialization. --- yunq/example/example.yunq | 2 +- yunq/example/example.yunq.cpp | 46 +++++++++++++++++++++--- yunq/example/example.yunq.h | 15 ++++---- yunq/example/example.yunq.server.cpp | 13 ++++--- yunq/message.cpp.jinja | 52 ++++++++++++++++++++++++++++ yunq/message.h.jinja | 10 ++++++ yunq/parser.py | 10 ++++-- 7 files changed, 127 insertions(+), 21 deletions(-) diff --git a/yunq/example/example.yunq b/yunq/example/example.yunq index c277322..5565354 100644 --- a/yunq/example/example.yunq +++ b/yunq/example/example.yunq @@ -4,7 +4,7 @@ interface VFS { message OpenFileRequest { string path; - u64 options; + repeated u64 options; } message File { diff --git a/yunq/example/example.yunq.cpp b/yunq/example/example.yunq.cpp index 0277829..91b30f5 100644 --- a/yunq/example/example.yunq.cpp +++ b/yunq/example/example.yunq.cpp @@ -34,7 +34,15 @@ void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t off set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length)); // Parse options. - set_options(bytes.At(offset + header_size + (8 * 1))); + auto options_pointer = bytes.At(offset + header_size + (8 * 1)) + + options_.Resize(options_pointer.length); + for (uint64_t i = offset + options_pointer.offset; + i < offset + options_pointer.offset + (sizeof(uint64_t) * options_pointer.length); + i += sizeof(uint64_t)) { + options_.PushBack(bytes.At(i)); + } + } void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { @@ -44,7 +52,15 @@ void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t off set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length)); // Parse options. - set_options(bytes.At(offset + header_size + (8 * 1))); + auto options_pointer = bytes.At(offset + header_size + (8 * 1)) + + options_.Resize(options_pointer.length); + for (uint64_t i = offset + options_pointer.offset; + i < offset + options_pointer.offset + (sizeof(uint64_t) * options_pointer.length); + i += sizeof(uint64_t)) { + options_.PushBack(bytes.At(i)); + } + } uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { @@ -62,7 +78,18 @@ uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t off bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); // Write options. - bytes.WriteAt(offset + header_size + (8 * 1), options()); + ExtPointer options_ptr{ + .offset = next_extension, + .length = (uint32_t)(options().size() * sizeof(uint64_t)), + }; + + next_extension += options_ptr.length; + bytes.WriteAt(offset + header_size + (8 * 1), options_ptr); + + for (uint64_t i = 0; i < options().size(); i++) { + uint32_t ext_offset = offset + options_ptr.offset + (i * sizeof(uint64_t)); + bytes.WriteAt(ext_offset, options().at(i)); + } // The next extension pointer is the length of the message. WriteHeader(bytes, offset, core_size, next_extension); @@ -86,7 +113,18 @@ uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t off bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); // Write options. - bytes.WriteAt(offset + header_size + (8 * 1), options()); + ExtPointer options_ptr{ + .offset = next_extension, + .length = (uint32_t)(options().size() * sizeof(uint64_t)), + }; + + next_extension += options_ptr.length; + bytes.WriteAt(offset + header_size + (8 * 1), options_ptr); + + for (uint64_t i = 0; i < options().size(); i++) { + uint32_t ext_offset = offset + options_ptr.offset + (i * sizeof(uint64_t)); + bytes.WriteAt(ext_offset, options().at(i)); + } // The next extension pointer is the length of the message. WriteHeader(bytes, offset, core_size, next_extension); diff --git a/yunq/example/example.yunq.h b/yunq/example/example.yunq.h index 8842491..7abd28e 100644 --- a/yunq/example/example.yunq.h +++ b/yunq/example/example.yunq.h @@ -3,6 +3,7 @@ #include #include +#include #include #include class OpenFileRequest { @@ -15,15 +16,15 @@ class OpenFileRequest { void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const; - uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; + uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; glcr::String path() const { return path_; } void set_path(const glcr::String& value) { path_ = value; } - uint64_t options() const { return options_; } - void set_options(const uint64_t& value) { options_ = value; } + const glcr::Vector& options() const { return options_; } + void add_options(const uint64_t& value) { options_.PushBack(value); } private: glcr::String path_; - uint64_t options_; + glcr::Vector options_; }; class File { @@ -36,11 +37,11 @@ class File { void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const; - uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; + uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; glcr::String path() const { return path_; } - void set_path(const glcr::String& value) { path_ = value; } + void set_path(const glcr::String& value) { path_ = value; } uint64_t attrs() const { return attrs_; } - void set_attrs(const uint64_t& value) { attrs_ = value; } + void set_attrs(const uint64_t& value) { attrs_ = value; } z_cap_t mem_cap() const { return mem_cap_; } void set_mem_cap(const z_cap_t& value) { mem_cap_ = value; } diff --git a/yunq/example/example.yunq.server.cpp b/yunq/example/example.yunq.server.cpp index 1adb3c6..8262388 100644 --- a/yunq/example/example.yunq.server.cpp +++ b/yunq/example/example.yunq.server.cpp @@ -31,8 +31,7 @@ void VFSServerBaseThreadBootstrap(void* server_base) { glcr::ErrorOr VFSServerBase::CreateClient() { uint64_t client_cap; - // FIXME: Restrict permissions to send-only here. - RET_ERR(ZCapDuplicate(endpoint_, &client_cap)); + RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap)); return VFSClient(client_cap); } @@ -51,9 +50,9 @@ void VFSServerBase::ServerThread() { uint64_t recv_cap_size = 0x10; uint64_t recv_buf_size = 0x1000; recv_cap.Reset(); - glcr::ErrorCode recv_err = ZEndpointRecv(endpoint_, &recv_buf_size, recv_buffer.RawPtr(), &recv_cap_size, recv_cap.RawPtr(), &reply_port_cap); + glcr::ErrorCode recv_err = static_cast(ZEndpointRecv(endpoint_, &recv_buf_size, recv_buffer.RawPtr(), &recv_cap_size, recv_cap.RawPtr(), &reply_port_cap)); if (recv_err != glcr::OK) { - dbgln("Error in receive: %x", recv_err); + dbgln("Error in receive: {x}", recv_err); continue; } @@ -64,13 +63,13 @@ void VFSServerBase::ServerThread() { glcr::ErrorCode err = HandleRequest(recv_buffer, recv_cap, resp_buffer, resp_length, resp_cap); if (err != glcr::OK) { WriteError(resp_buffer, err); - reply_err = ZReplyPortSend(reply_port_cap, kHeaderSize, resp_buffer.RawPtr(), 0, nullptr); + reply_err = static_cast(ZReplyPortSend(reply_port_cap, kHeaderSize, resp_buffer.RawPtr(), 0, nullptr)); } else { WriteHeader(resp_buffer, resp_length); - reply_err = ZReplyPortSend(reply_port_cap, kHeaderSize + resp_length, resp_buffer.RawPtr(), resp_cap.UsedSlots(), resp_cap.RawPtr()); + reply_err = static_cast(ZReplyPortSend(reply_port_cap, kHeaderSize + resp_length, resp_buffer.RawPtr(), resp_cap.UsedSlots(), resp_cap.RawPtr())); } if (reply_err != glcr::OK) { - dbgln("Error in reply: %x", reply_err); + dbgln("Error in reply: {x}", reply_err); } } diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index 34abcdd..296d0dc 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -34,6 +34,7 @@ void {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of {%- for field in message.fields %} // Parse {{field.name}}. +{%- if not field.repeated %} {%- if field.type == Type.U64 %} set_{{field.name}}(bytes.At(offset + header_size + (8 * {{loop.index0}}))); {%- elif field.type == Type.I64 %} @@ -48,6 +49,16 @@ void {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of {%- else %} // TODO: Unimplemented parsing {{field.type}} {%- endif %} +{%- else %} + auto {{field.name}}_pointer = bytes.At(offset + header_size + (8 * {{loop.index0}})); + + {{field.name}}_.Resize({{field.name}}_pointer.length); + for (uint64_t i = offset + {{field.name}}_pointer.offset; + i < offset + {{field.name}}_pointer.offset + (sizeof({{field.cpp_type()}}) * {{field.name}}_pointer.length); + i += sizeof({{field.cpp_type()}})) { + {{field.name}}_.PushBack(bytes.At<{{field.cpp_type()}}>(i)); + } +{% endif %} {%- endfor %} } @@ -56,6 +67,7 @@ void {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of {%- for field in message.fields %} // Parse {{field.name}}. +{%- if not field.repeated %} {%- if field.type == Type.U64 %} set_{{field.name}}(bytes.At(offset + header_size + (8 * {{loop.index0}}))); {%- elif field.type == Type.I64 %} @@ -71,6 +83,16 @@ void {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of {%- else %} // TODO: Unimplemented parsing {{field.type}} {%- endif %} +{%- else %} + auto {{field.name}}_pointer = bytes.At(offset + header_size + (8 * {{loop.index0}})); + + {{field.name}}_.Resize({{field.name}}_pointer.length); + for (uint64_t i = offset + {{field.name}}_pointer.offset; + i < offset + {{field.name}}_pointer.offset + (sizeof({{field.cpp_type()}}) * {{field.name}}_pointer.length); + i += sizeof({{field.cpp_type()}})) { + {{field.name}}_.PushBack(bytes.At<{{field.cpp_type()}}>(i)); + } +{% endif %} {%- endfor %} } @@ -80,6 +102,7 @@ uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t of {%- for field in message.fields %} // Write {{field.name}}. +{%- if not field.repeated %} {%- if field.type == Type.U64 %} bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}()); {%- elif field.type == Type.I64 %} @@ -101,6 +124,20 @@ uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t of {%- else %} // TODO: Unimplemented serialization {{field.type}} {%- endif %} +{%- else %} + ExtPointer {{field.name}}_ptr{ + .offset = next_extension, + .length = (uint32_t)({{field.name}}().size() * sizeof({{field.cpp_type()}})), + }; + + next_extension += {{field.name}}_ptr.length; + bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}_ptr); + + for (uint64_t i = 0; i < {{field.name}}().size(); i++) { + uint32_t ext_offset = offset + {{field.name}}_ptr.offset + (i * sizeof({{field.cpp_type()}})); + bytes.WriteAt<{{field.cpp_type()}}>(ext_offset, {{field.name}}().at(i)); + } +{%- endif %} {%- endfor %} // The next extension pointer is the length of the message. @@ -116,6 +153,7 @@ uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t of {%- for field in message.fields %} // Write {{field.name}}. +{%- if not field.repeated %} {%- if field.type == Type.U64 %} bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}()); {%- elif field.type == Type.I64 %} @@ -137,6 +175,20 @@ uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t of {%- else %} // TODO: Unimplemented serialization {{field.type}} {%- endif %} +{%- else %} + ExtPointer {{field.name}}_ptr{ + .offset = next_extension, + .length = (uint32_t)({{field.name}}().size() * sizeof({{field.cpp_type()}})), + }; + + next_extension += {{field.name}}_ptr.length; + bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}_ptr); + + for (uint64_t i = 0; i < {{field.name}}().size(); i++) { + uint32_t ext_offset = offset + {{field.name}}_ptr.offset + (i * sizeof({{field.cpp_type()}})); + bytes.WriteAt<{{field.cpp_type()}}>(ext_offset, {{field.name}}().at(i)); + } +{%- endif %} {%- endfor %} // The next extension pointer is the length of the message. diff --git a/yunq/message.h.jinja b/yunq/message.h.jinja index 68adbfb..058b970 100644 --- a/yunq/message.h.jinja +++ b/yunq/message.h.jinja @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -21,13 +22,22 @@ class {{message.name}} { uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; {%- for field in message.fields %} + {%- if not field.repeated %} {{field.cpp_type()}} {{field.name}}() const { return {{field.name}}_; } void set_{{field.name}}(const {{field.cpp_type()}}& value) { {{field.name}}_ = value; } + {%- else %} + const glcr::Vector<{{field.cpp_type()}}>& {{field.name}}() const { return {{field.name}}_; } + void add_{{field.name}}(const {{field.cpp_type()}}& value) { {{field.name}}_.PushBack(value); } + {%- endif %} {%- endfor %} private: {%- for field in message.fields %} + {%- if not field.repeated %} {{field.cpp_type()}} {{field.name}}_; + {%- else %} + glcr::Vector<{{field.cpp_type()}}> {{field.name}}_; + {%- endif %} {%- endfor %} }; diff --git a/yunq/parser.py b/yunq/parser.py index 41b680c..2cc9f40 100644 --- a/yunq/parser.py +++ b/yunq/parser.py @@ -114,9 +114,10 @@ type_to_cppstr = { } class Field(): - def __init__(self, fieldtype: Type, name: str): + def __init__(self, fieldtype: Type, name: str, repeated = False): self.type = fieldtype self.name = name + self.repeated = repeated def cpp_type(self): return type_to_cppstr[self.type] @@ -250,14 +251,19 @@ class Parser(): def field(self): + repeated = False field_type_str = self.consume_identifier() + if field_type_str == "repeated": + repeated = True + field_type_str = self.consume_identifier() + if field_type_str not in type_str_dict.keys(): sys.exit("Expected type got '%s'" % field_type_str) field_type = type_str_dict[field_type_str] name = self.consume_identifier() self.consume_check(LexemeType.SEMICOLON) - return Field(field_type, name) + return Field(field_type, name, repeated) def type_check(decls: list[Decl]): for decl in decls: