Compare commits
2 Commits
3faa19e4cb
...
71e3521b87
Author | SHA1 | Date |
---|---|---|
|
71e3521b87 | |
|
963cc0b4fa |
|
@ -30,6 +30,7 @@ static const uint64_t FAILED_PRECONDITION = 0x8;
|
||||||
static const uint64_t INTERNAL = 0x100;
|
static const uint64_t INTERNAL = 0x100;
|
||||||
static const uint64_t UNIMPLEMENTED = 0x101;
|
static const uint64_t UNIMPLEMENTED = 0x101;
|
||||||
static const uint64_t EXHAUSTED = 0x102;
|
static const uint64_t EXHAUSTED = 0x102;
|
||||||
|
static const uint64_t INVALID_RESPONSE = 0x103;
|
||||||
|
|
||||||
// Kernel specific error codes (relating to capabilities).
|
// Kernel specific error codes (relating to capabilities).
|
||||||
static const uint64_t CAP_NOT_FOUND = 0x1000;
|
static const uint64_t CAP_NOT_FOUND = 0x1000;
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Generated file - DO NOT MODIFY
|
||||||
|
#include "{{file}}.client.h"
|
||||||
|
|
||||||
|
#include <glacier/buffer/byte_buffer.h>
|
||||||
|
#include <glacier/buffer/cap_buffer.h>
|
||||||
|
|
||||||
|
{% for interface in interfaces %}
|
||||||
|
{% for method in interface.methods %}
|
||||||
|
|
||||||
|
glcr::ErrorCode {{method.name}}(const {{method.request}}& request, {{method.response}}& response) {
|
||||||
|
uint64_t buffer_size = 0x1000;
|
||||||
|
// FIXME: Maybe raise this limit.
|
||||||
|
uint64_t cap_size = 100;
|
||||||
|
glcr::ByteBuffer buffer(buffer_size);
|
||||||
|
glcr::CapBuffer caps(cap_size);
|
||||||
|
|
||||||
|
const uint32_t kSentinel = 0xBEEFDEAD;
|
||||||
|
buffer.WriteAt<uint32_t>(0, kSentinel);
|
||||||
|
buffer.WriteAt<uint64_t>(8, {method_number});
|
||||||
|
|
||||||
|
uint64_t length = request.SerializeToBytes(buffer, /*offset=*/16, caps);
|
||||||
|
buffer.WriteAt<uint32_t>(4, 16 + length);
|
||||||
|
|
||||||
|
z_cap_t reply_port_cap;
|
||||||
|
// FIXME: We need to be able to send capabilities via endpoint call.
|
||||||
|
RET_ERR(ZEndpointSend(endpoint_, 16 + length, buffer.RawPtr()));
|
||||||
|
|
||||||
|
// FIXME: Add a way to zero out the first buffer.
|
||||||
|
glcr::ByteBuffer recv_buffer(buffer_size);
|
||||||
|
glcr::CapBuffer recv_caps(cap_size);
|
||||||
|
RET_ERR(ZReplyPortRecv(reply_port_cap, &buffer_size, recv_buffer.RawPtr(), &cap_size, recv_caps.RawPtr()));
|
||||||
|
|
||||||
|
if (recv_buffer.At<uint32_t>(0) != kSentinel) {
|
||||||
|
return glcr::INVALID_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Response Code.
|
||||||
|
RET_ERR(recv_buffer.At<uint64_t>(8));
|
||||||
|
|
||||||
|
response.ParseFromBytes(recv_buffer, 16, recv_caps);
|
||||||
|
|
||||||
|
return glcr::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
|
@ -0,0 +1,22 @@
|
||||||
|
// Generated file - DO NOT MODIFY
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ztypes.h>
|
||||||
|
|
||||||
|
#include "{{file}}.h"
|
||||||
|
|
||||||
|
{% for interface in interfaces -%}
|
||||||
|
class {{interface.name}}Client {
|
||||||
|
public:
|
||||||
|
{{interface.name}}Client(z_cap_t {{interface.name}}_cap) : endpoint_({{interface.name}}_cap) {}
|
||||||
|
{{interface.name}}Client(const {{interface.name}}Client&) = delete;
|
||||||
|
{{interface.name}}Client({{interface.name}}Client&&) = delete;
|
||||||
|
{% for method in interface.methods %}
|
||||||
|
[[nodiscard]] glcr::ErrorCode {{method.name}}(const {{method.request}}& request, {{method.response}}& response);
|
||||||
|
{% endfor %}
|
||||||
|
private:
|
||||||
|
z_cap_t endpoint_;
|
||||||
|
};
|
||||||
|
|
||||||
|
{%- endfor %}
|
||||||
|
|
|
@ -1,267 +0,0 @@
|
||||||
|
|
||||||
from parser import *
|
|
||||||
|
|
||||||
HEADER_PRELUDE = """
|
|
||||||
// Generated file - DO NOT MODIFY
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <glacier/buffer/byte_buffer.h>
|
|
||||||
#include <glacier/buffer/cap_buffer.h>
|
|
||||||
#include <glacier/string/string.h>
|
|
||||||
#include <ztypes.h>
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
MESSAGE_CLASS_PREFIX = """
|
|
||||||
class {name} {{
|
|
||||||
public:
|
|
||||||
{name}() {{}}
|
|
||||||
// Delete copy and move until implemented.
|
|
||||||
{name}(const {name}&) = delete;
|
|
||||||
{name}({name}&&) = delete;
|
|
||||||
|
|
||||||
void ParseFromBytes(const glcr::ByteBuffer&);
|
|
||||||
void ParseFromBytes(const glcr::ByteBuffer&, const glcr::CapBuffer&);
|
|
||||||
void SerializeToBytes(glcr::ByteBuffer&);
|
|
||||||
void SerializeToBytes(glcr::ByteBuffer&, glcr::CapBuffer&);
|
|
||||||
"""
|
|
||||||
|
|
||||||
MESSAGE_CLASS_SET_GET = """
|
|
||||||
{type} {name}() {{ return {name}_; }}
|
|
||||||
void set_{name}({type} value) {{
|
|
||||||
{name}_ = value;
|
|
||||||
}}
|
|
||||||
"""
|
|
||||||
|
|
||||||
MESSAGE_CLASS_PRIVATE = """
|
|
||||||
private:
|
|
||||||
"""
|
|
||||||
|
|
||||||
MESSAGE_CLASS_FIELD = """
|
|
||||||
{type} {name}_;
|
|
||||||
"""
|
|
||||||
|
|
||||||
MESSAGE_CLASS_SUFFIX = """
|
|
||||||
};
|
|
||||||
"""
|
|
||||||
|
|
||||||
type_to_str = {
|
|
||||||
Type.U64: "uint64_t",
|
|
||||||
Type.I64: "int64_t",
|
|
||||||
Type.STRING: "glcr::String",
|
|
||||||
Type.CAPABILITY: "z_cap_t",
|
|
||||||
Type.BYTES: "glcr::Vector<uint8_t>"
|
|
||||||
}
|
|
||||||
|
|
||||||
def _type_str(field_type: Type) -> str:
|
|
||||||
return type_to_str[field_type]
|
|
||||||
|
|
||||||
|
|
||||||
def _generate_message_class(message: Message) -> str:
|
|
||||||
class_decl = MESSAGE_CLASS_PREFIX.format(name = message.name)
|
|
||||||
|
|
||||||
for field in message.fields:
|
|
||||||
class_decl += MESSAGE_CLASS_SET_GET.format(name = field.name, type = _type_str(field.type))
|
|
||||||
|
|
||||||
class_decl += MESSAGE_CLASS_PRIVATE
|
|
||||||
|
|
||||||
for field in message.fields:
|
|
||||||
class_decl += MESSAGE_CLASS_FIELD.format(name = field.name, type = _type_str(field.type))
|
|
||||||
|
|
||||||
class_decl += MESSAGE_CLASS_SUFFIX
|
|
||||||
return class_decl
|
|
||||||
|
|
||||||
|
|
||||||
def generate_message_header(ast: list[Decl]) -> str:
|
|
||||||
header = HEADER_PRELUDE
|
|
||||||
|
|
||||||
for decl in ast:
|
|
||||||
if type(decl) != Message:
|
|
||||||
continue
|
|
||||||
header += _generate_message_class(decl)
|
|
||||||
|
|
||||||
return header
|
|
||||||
|
|
||||||
IMPL_PRELUDE = """
|
|
||||||
#include "{file}.h"
|
|
||||||
|
|
||||||
namespace {{
|
|
||||||
|
|
||||||
const uint64_t header_size = 24; // 4x uint32, 1x uint64
|
|
||||||
|
|
||||||
struct ExtPointer {{
|
|
||||||
uint32_t offset;
|
|
||||||
uint32_t length;
|
|
||||||
}};
|
|
||||||
|
|
||||||
void CheckHeader(const glcr::ByteBuffer& bytes) {{
|
|
||||||
// TODO: Check ident.
|
|
||||||
// TODO: Parse core size.
|
|
||||||
// TODO: Parse extension size.
|
|
||||||
// TODO: Check CRC32
|
|
||||||
// TODO: Parse options.
|
|
||||||
}}
|
|
||||||
|
|
||||||
void WriteHeader(glcr::ByteBuffer& bytes, uint32_t core_size, uint32_t extension_size) {{
|
|
||||||
bytes.WriteAt<uint32_t>(0, 0xDEADBEEF); // TODO: Chose a more unique ident sequence.
|
|
||||||
bytes.WriteAt<uint32_t>(4, core_size);
|
|
||||||
bytes.WriteAt<uint32_t>(8, extension_size);
|
|
||||||
bytes.WriteAt<uint32_t>(12, 0); // TODO: Calculate CRC32.
|
|
||||||
bytes.WriteAt<uint64_t>(16, 0); // TODO: Add options.
|
|
||||||
}}
|
|
||||||
|
|
||||||
}} // namespace
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_PARSE_DEF = """
|
|
||||||
void {name}::ParseFromBytes(const glcr::ByteBuffer& bytes) {{
|
|
||||||
CheckHeader(bytes);
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_PARSE_DEF_CAP = """
|
|
||||||
void {name}::ParseFromBytes(const glcr::ByteBuffer& bytes, const glcr::CapBuffer& caps) {{
|
|
||||||
CheckHeader(bytes);
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_PARSE_U64 = """
|
|
||||||
set_{name}(bytes.At<uint64_t>(header_size + (8 * {offset})));
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_PARSE_I64 = """
|
|
||||||
set_{name}(bytes.At<int64_t>(header_size + (8 * {offset})));
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_PARSE_STRING = """
|
|
||||||
auto {name}_pointer = bytes.At<ExtPointer>(header_size + (8 * {offset}));
|
|
||||||
|
|
||||||
set_{name}(bytes.StringAt({name}_pointer.offset, {name}_pointer.length));
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_SET_CAP_EMPTY = """
|
|
||||||
set_{name}(0);
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_PARSE_CAP = """
|
|
||||||
uint64_t {name}_ptr = bytes.At<uint64_t>(header_size + (8 * {offset}));
|
|
||||||
|
|
||||||
set_{name}(caps.At({name}_ptr));
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_PARSE_DEF_END = """
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _generate_message_parse_impl(message: Message) -> str:
|
|
||||||
impl = ""
|
|
||||||
|
|
||||||
for with_cap in (False, True):
|
|
||||||
impl += IMPL_PARSE_DEF.format(name=message.name) if not with_cap else IMPL_PARSE_DEF_CAP.format(name=message.name)
|
|
||||||
for offset, field in enumerate(message.fields):
|
|
||||||
if field.type == Type.U64:
|
|
||||||
impl += IMPL_PARSE_U64.format(name = field.name, offset = offset)
|
|
||||||
elif field.type == Type.I64:
|
|
||||||
impl += IMPL_PARSE_I64.format(name = field.name, offset = offset)
|
|
||||||
elif field.type == Type.STRING:
|
|
||||||
impl += IMPL_PARSE_STRING.format(name = field.name, offset = offset);
|
|
||||||
elif field.type == Type.CAPABILITY:
|
|
||||||
if with_cap:
|
|
||||||
impl += IMPL_PARSE_CAP.format(name = field.name, offset = offset)
|
|
||||||
else:
|
|
||||||
impl += IMPL_SET_CAP_EMPTY.format(name = field.name)
|
|
||||||
else:
|
|
||||||
impl += "\n{} unimplemented\n".format(field.type.name)
|
|
||||||
|
|
||||||
impl += IMPL_PARSE_DEF_END
|
|
||||||
|
|
||||||
return impl
|
|
||||||
|
|
||||||
IMPL_SER_DEF = """
|
|
||||||
void {name}::SerializeToBytes(glcr::ByteBuffer& bytes) {{
|
|
||||||
|
|
||||||
uint32_t next_extension = header_size + 8 * {num_fields};
|
|
||||||
const uint32_t core_size = next_extension;
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_SER_CAP_DEF = """
|
|
||||||
void {name}::SerializeToBytes(glcr::ByteBuffer& bytes, glcr::CapBuffer& caps) {{
|
|
||||||
|
|
||||||
uint32_t next_extension = header_size + 8 * {num_fields};
|
|
||||||
const uint32_t core_size = next_extension;
|
|
||||||
uint64_t next_cap = 0;
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_SER_U64 = """
|
|
||||||
bytes.WriteAt<uint64_t>(header_size + (8 * {offset}), {name}());
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_SER_I64 = """
|
|
||||||
bytes.WriteAt<int64_t>(header_size + (8 * {offset}), {name}());
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_SER_STRING = """
|
|
||||||
ExtPointer {name}_ptr{{
|
|
||||||
.offset = next_extension,
|
|
||||||
// FIXME: Check downcast of str length.
|
|
||||||
.length = (uint32_t){name}().length(),
|
|
||||||
}};
|
|
||||||
|
|
||||||
bytes.WriteStringAt(next_extension, {name}());
|
|
||||||
next_extension += {name}_ptr.length;
|
|
||||||
|
|
||||||
bytes.WriteAt<ExtPointer>(header_size + (8 * {offset}), {name}_ptr);
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_SER_CAP_EMPTY = """
|
|
||||||
// FIXME: Warn or error on serialization
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_SER_CAP = """
|
|
||||||
caps.WriteAt(next_cap, {name}());
|
|
||||||
bytes.WriteAt<uint64_t>(header_size + (8 * {offset}), next_cap++);
|
|
||||||
"""
|
|
||||||
|
|
||||||
IMPL_SER_DEF_END = """
|
|
||||||
// The next extension pointer is the length of the message.
|
|
||||||
WriteHeader(bytes, core_size, next_extension);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
def _generate_message_serialize_impl(message: Message) -> str:
|
|
||||||
impl = ""
|
|
||||||
|
|
||||||
for with_cap in (False, True):
|
|
||||||
if with_cap:
|
|
||||||
impl += IMPL_SER_CAP_DEF.format(name = message.name, num_fields = len(message.fields))
|
|
||||||
else:
|
|
||||||
impl += IMPL_SER_DEF.format(name = message.name, num_fields = len(message.fields))
|
|
||||||
|
|
||||||
for offset, field in enumerate(message.fields):
|
|
||||||
if field.type == Type.U64:
|
|
||||||
impl += IMPL_SER_U64.format(name = field.name, offset = offset)
|
|
||||||
elif field.type == Type.I64:
|
|
||||||
impl += IMPL_SER_I64.format(name = field.name, offset = offset)
|
|
||||||
elif field.type == Type.STRING:
|
|
||||||
impl += IMPL_SER_STRING.format(name = field.name, offset = offset)
|
|
||||||
elif field.type == Type.CAPABILITY:
|
|
||||||
if with_cap:
|
|
||||||
impl += IMPL_SER_CAP.format(name = field.name, offset = offset)
|
|
||||||
else:
|
|
||||||
impl += IMPL_SER_CAP_EMPTY
|
|
||||||
else:
|
|
||||||
impl += "\n{} unimplemented\n".format(field.type.name)
|
|
||||||
impl += IMPL_SER_DEF_END
|
|
||||||
|
|
||||||
return impl
|
|
||||||
|
|
||||||
def _generate_message_class_impl(message: Message) -> str:
|
|
||||||
return _generate_message_parse_impl(message) + _generate_message_serialize_impl(message)
|
|
||||||
|
|
||||||
|
|
||||||
def generate_message_impl(file: str, ast: list[Decl]) -> str:
|
|
||||||
impl = IMPL_PRELUDE.format(file=file)
|
|
||||||
|
|
||||||
for decl in ast:
|
|
||||||
if type(decl) != Message:
|
|
||||||
continue
|
|
||||||
impl += _generate_message_class_impl(decl)
|
|
||||||
|
|
||||||
return impl
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Generated file - DO NOT MODIFY
|
||||||
|
#include "example.yunq.client.h"
|
||||||
|
|
||||||
|
#include <glacier/buffer/byte_buffer.h>
|
||||||
|
#include <glacier/buffer/cap_buffer.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
glcr::ErrorCode open(const OpenFileRequest& request, File& response) {
|
||||||
|
uint64_t buffer_size = 0x1000;
|
||||||
|
// FIXME: Maybe raise this limit.
|
||||||
|
uint64_t cap_size = 100;
|
||||||
|
glcr::ByteBuffer buffer(buffer_size);
|
||||||
|
glcr::CapBuffer caps(cap_size);
|
||||||
|
|
||||||
|
const uint32_t kSentinel = 0xBEEFDEAD;
|
||||||
|
buffer.WriteAt<uint32_t>(0, kSentinel);
|
||||||
|
buffer.WriteAt<uint64_t>(8, {method_number});
|
||||||
|
|
||||||
|
uint64_t length = request.SerializeToBytes(buffer, /*offset=*/16, caps);
|
||||||
|
buffer.WriteAt<uint32_t>(4, 16 + length);
|
||||||
|
|
||||||
|
z_cap_t reply_port_cap;
|
||||||
|
// FIXME: We need to be able to send capabilities via endpoint call.
|
||||||
|
RET_ERR(ZEndpointSend(endpoint_, 16 + length, buffer.RawPtr()));
|
||||||
|
|
||||||
|
// FIXME: Add a way to zero out the first buffer.
|
||||||
|
glcr::ByteBuffer recv_buffer(buffer_size);
|
||||||
|
glcr::CapBuffer recv_caps(cap_size);
|
||||||
|
RET_ERR(ZReplyPortRecv(reply_port_cap, &buffer_size, recv_buffer.RawPtr(), &cap_size, recv_caps.RawPtr()));
|
||||||
|
|
||||||
|
if (recv_buffer.At<uint32_t>(0) != kSentinel) {
|
||||||
|
return glcr::INVALID_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Response Code.
|
||||||
|
RET_ERR(recv_buffer.At<uint64_t>(8));
|
||||||
|
|
||||||
|
response.ParseFromBytes(recv_buffer, 16, recv_caps);
|
||||||
|
|
||||||
|
return glcr::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Generated file - DO NOT MODIFY
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ztypes.h>
|
||||||
|
|
||||||
|
#include "example.yunq.h"
|
||||||
|
|
||||||
|
class VFSClient {
|
||||||
|
public:
|
||||||
|
VFSClient(z_cap_t VFS_cap) : endpoint_(VFS_cap) {}
|
||||||
|
VFSClient(const VFSClient&) = delete;
|
||||||
|
VFSClient(VFSClient&&) = delete;
|
||||||
|
|
||||||
|
[[nodiscard]] glcr::ErrorCode open(const OpenFileRequest& request, File& response);
|
||||||
|
|
||||||
|
private:
|
||||||
|
z_cap_t endpoint_;
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
|
// Generated file -- DO NOT MODIFY.
|
||||||
#include "example.yunq.h"
|
#include "example.yunq.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -18,157 +18,157 @@ void CheckHeader(const glcr::ByteBuffer& bytes) {
|
||||||
// TODO: Parse options.
|
// TODO: Parse options.
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteHeader(glcr::ByteBuffer& bytes, uint32_t core_size, uint32_t extension_size) {
|
void WriteHeader(glcr::ByteBuffer& bytes, uint64_t offset, uint32_t core_size, uint32_t extension_size) {
|
||||||
bytes.WriteAt<uint32_t>(0, 0xDEADBEEF); // TODO: Chose a more unique ident sequence.
|
bytes.WriteAt<uint32_t>(offset + 0, 0xDEADBEEF); // TODO: Chose a more unique ident sequence.
|
||||||
bytes.WriteAt<uint32_t>(4, core_size);
|
bytes.WriteAt<uint32_t>(offset + 4, core_size);
|
||||||
bytes.WriteAt<uint32_t>(8, extension_size);
|
bytes.WriteAt<uint32_t>(offset + 8, extension_size);
|
||||||
bytes.WriteAt<uint32_t>(12, 0); // TODO: Calculate CRC32.
|
bytes.WriteAt<uint32_t>(offset + 12, 0); // TODO: Calculate CRC32.
|
||||||
bytes.WriteAt<uint64_t>(16, 0); // TODO: Add options.
|
bytes.WriteAt<uint64_t>(offset + 16, 0); // TODO: Add options.
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) {
|
||||||
void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes) {
|
|
||||||
CheckHeader(bytes);
|
CheckHeader(bytes);
|
||||||
|
// Parse path.
|
||||||
|
auto path_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * 0));
|
||||||
|
|
||||||
auto path_pointer = bytes.At<ExtPointer>(header_size + (8 * 0));
|
set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length));
|
||||||
|
// Parse options.
|
||||||
set_path(bytes.StringAt(path_pointer.offset, path_pointer.length));
|
set_options(bytes.At<uint64_t>(offset + header_size + (8 * 1)));
|
||||||
|
|
||||||
set_options(bytes.At<uint64_t>(header_size + (8 * 1)));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, const glcr::CapBuffer& caps) {
|
void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) {
|
||||||
CheckHeader(bytes);
|
CheckHeader(bytes);
|
||||||
|
// Parse path.
|
||||||
|
auto path_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * 0));
|
||||||
|
|
||||||
auto path_pointer = bytes.At<ExtPointer>(header_size + (8 * 0));
|
set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length));
|
||||||
|
// Parse options.
|
||||||
set_path(bytes.StringAt(path_pointer.offset, path_pointer.length));
|
set_options(bytes.At<uint64_t>(offset + header_size + (8 * 1)));
|
||||||
|
|
||||||
set_options(bytes.At<uint64_t>(header_size + (8 * 1)));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes) {
|
uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) {
|
||||||
|
|
||||||
uint32_t next_extension = header_size + 8 * 2;
|
uint32_t next_extension = header_size + 8 * 2;
|
||||||
const uint32_t core_size = next_extension;
|
const uint32_t core_size = next_extension;
|
||||||
|
// Write path.
|
||||||
ExtPointer path_ptr{
|
ExtPointer path_ptr{
|
||||||
.offset = next_extension,
|
.offset = next_extension,
|
||||||
// FIXME: Check downcast of str length.
|
// FIXME: Check downcast of str length.
|
||||||
.length = (uint32_t)path().length(),
|
.length = (uint32_t)path().length(),
|
||||||
};
|
};
|
||||||
|
|
||||||
bytes.WriteStringAt(next_extension, path());
|
bytes.WriteStringAt(offset + next_extension, path());
|
||||||
next_extension += path_ptr.length;
|
next_extension += path_ptr.length;
|
||||||
|
|
||||||
bytes.WriteAt<ExtPointer>(header_size + (8 * 0), path_ptr);
|
bytes.WriteAt<ExtPointer>(offset + header_size + (8 * 0), path_ptr);
|
||||||
|
// Write options.
|
||||||
bytes.WriteAt<uint64_t>(header_size + (8 * 1), options());
|
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 1), options());
|
||||||
|
|
||||||
// The next extension pointer is the length of the message.
|
// The next extension pointer is the length of the message.
|
||||||
WriteHeader(bytes, core_size, next_extension);
|
WriteHeader(bytes, offset, core_size, next_extension);
|
||||||
|
|
||||||
|
return next_extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, glcr::CapBuffer& caps) {
|
uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) {
|
||||||
|
|
||||||
uint32_t next_extension = header_size + 8 * 2;
|
uint32_t next_extension = header_size + 8 * 2;
|
||||||
const uint32_t core_size = next_extension;
|
const uint32_t core_size = next_extension;
|
||||||
uint64_t next_cap = 0;
|
uint64_t next_cap = 0;
|
||||||
|
// Write path.
|
||||||
ExtPointer path_ptr{
|
ExtPointer path_ptr{
|
||||||
.offset = next_extension,
|
.offset = next_extension,
|
||||||
// FIXME: Check downcast of str length.
|
// FIXME: Check downcast of str length.
|
||||||
.length = (uint32_t)path().length(),
|
.length = (uint32_t)path().length(),
|
||||||
};
|
};
|
||||||
|
|
||||||
bytes.WriteStringAt(next_extension, path());
|
bytes.WriteStringAt(offset + next_extension, path());
|
||||||
next_extension += path_ptr.length;
|
next_extension += path_ptr.length;
|
||||||
|
|
||||||
bytes.WriteAt<ExtPointer>(header_size + (8 * 0), path_ptr);
|
bytes.WriteAt<ExtPointer>(offset + header_size + (8 * 0), path_ptr);
|
||||||
|
// Write options.
|
||||||
bytes.WriteAt<uint64_t>(header_size + (8 * 1), options());
|
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 1), options());
|
||||||
|
|
||||||
// The next extension pointer is the length of the message.
|
// The next extension pointer is the length of the message.
|
||||||
WriteHeader(bytes, core_size, next_extension);
|
WriteHeader(bytes, offset, core_size, next_extension);
|
||||||
|
|
||||||
|
return next_extension;
|
||||||
}
|
}
|
||||||
|
void File::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) {
|
||||||
void File::ParseFromBytes(const glcr::ByteBuffer& bytes) {
|
|
||||||
CheckHeader(bytes);
|
CheckHeader(bytes);
|
||||||
|
// Parse path.
|
||||||
|
auto path_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * 0));
|
||||||
|
|
||||||
auto path_pointer = bytes.At<ExtPointer>(header_size + (8 * 0));
|
set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length));
|
||||||
|
// Parse attrs.
|
||||||
set_path(bytes.StringAt(path_pointer.offset, path_pointer.length));
|
set_attrs(bytes.At<uint64_t>(offset + header_size + (8 * 1)));
|
||||||
|
// Parse mem_cap.
|
||||||
set_attrs(bytes.At<uint64_t>(header_size + (8 * 1)));
|
// FIXME: Implement in-buffer capabilities for inprocess serialization.
|
||||||
|
|
||||||
set_mem_cap(0);
|
set_mem_cap(0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void File::ParseFromBytes(const glcr::ByteBuffer& bytes, const glcr::CapBuffer& caps) {
|
void File::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) {
|
||||||
CheckHeader(bytes);
|
CheckHeader(bytes);
|
||||||
|
// Parse path.
|
||||||
|
auto path_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * 0));
|
||||||
|
|
||||||
auto path_pointer = bytes.At<ExtPointer>(header_size + (8 * 0));
|
set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length));
|
||||||
|
// Parse attrs.
|
||||||
set_path(bytes.StringAt(path_pointer.offset, path_pointer.length));
|
set_attrs(bytes.At<uint64_t>(offset + header_size + (8 * 1)));
|
||||||
|
// Parse mem_cap.
|
||||||
set_attrs(bytes.At<uint64_t>(header_size + (8 * 1)));
|
uint64_t mem_cap_ptr = bytes.At<uint64_t>(offset + header_size + (8 * 2));
|
||||||
|
|
||||||
uint64_t mem_cap_ptr = bytes.At<uint64_t>(header_size + (8 * 2));
|
|
||||||
|
|
||||||
set_mem_cap(caps.At(mem_cap_ptr));
|
set_mem_cap(caps.At(mem_cap_ptr));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void File::SerializeToBytes(glcr::ByteBuffer& bytes) {
|
uint64_t File::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) {
|
||||||
|
|
||||||
uint32_t next_extension = header_size + 8 * 3;
|
uint32_t next_extension = header_size + 8 * 3;
|
||||||
const uint32_t core_size = next_extension;
|
const uint32_t core_size = next_extension;
|
||||||
|
// Write path.
|
||||||
ExtPointer path_ptr{
|
ExtPointer path_ptr{
|
||||||
.offset = next_extension,
|
.offset = next_extension,
|
||||||
// FIXME: Check downcast of str length.
|
// FIXME: Check downcast of str length.
|
||||||
.length = (uint32_t)path().length(),
|
.length = (uint32_t)path().length(),
|
||||||
};
|
};
|
||||||
|
|
||||||
bytes.WriteStringAt(next_extension, path());
|
bytes.WriteStringAt(offset + next_extension, path());
|
||||||
next_extension += path_ptr.length;
|
next_extension += path_ptr.length;
|
||||||
|
|
||||||
bytes.WriteAt<ExtPointer>(header_size + (8 * 0), path_ptr);
|
bytes.WriteAt<ExtPointer>(offset + header_size + (8 * 0), path_ptr);
|
||||||
|
// Write attrs.
|
||||||
bytes.WriteAt<uint64_t>(header_size + (8 * 1), attrs());
|
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 1), attrs());
|
||||||
|
// Write mem_cap.
|
||||||
// FIXME: Warn or error on serialization
|
// FIXME: Implement inbuffer capabilities.
|
||||||
|
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 2), 0);
|
||||||
|
|
||||||
// The next extension pointer is the length of the message.
|
// The next extension pointer is the length of the message.
|
||||||
WriteHeader(bytes, core_size, next_extension);
|
WriteHeader(bytes, offset, core_size, next_extension);
|
||||||
|
|
||||||
|
return next_extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
void File::SerializeToBytes(glcr::ByteBuffer& bytes, glcr::CapBuffer& caps) {
|
uint64_t File::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) {
|
||||||
|
|
||||||
uint32_t next_extension = header_size + 8 * 3;
|
uint32_t next_extension = header_size + 8 * 3;
|
||||||
const uint32_t core_size = next_extension;
|
const uint32_t core_size = next_extension;
|
||||||
uint64_t next_cap = 0;
|
uint64_t next_cap = 0;
|
||||||
|
// Write path.
|
||||||
ExtPointer path_ptr{
|
ExtPointer path_ptr{
|
||||||
.offset = next_extension,
|
.offset = next_extension,
|
||||||
// FIXME: Check downcast of str length.
|
// FIXME: Check downcast of str length.
|
||||||
.length = (uint32_t)path().length(),
|
.length = (uint32_t)path().length(),
|
||||||
};
|
};
|
||||||
|
|
||||||
bytes.WriteStringAt(next_extension, path());
|
bytes.WriteStringAt(offset + next_extension, path());
|
||||||
next_extension += path_ptr.length;
|
next_extension += path_ptr.length;
|
||||||
|
|
||||||
bytes.WriteAt<ExtPointer>(header_size + (8 * 0), path_ptr);
|
bytes.WriteAt<ExtPointer>(offset + header_size + (8 * 0), path_ptr);
|
||||||
|
// Write attrs.
|
||||||
bytes.WriteAt<uint64_t>(header_size + (8 * 1), attrs());
|
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 1), attrs());
|
||||||
|
// Write mem_cap.
|
||||||
caps.WriteAt(next_cap, mem_cap());
|
caps.WriteAt(next_cap, mem_cap());
|
||||||
bytes.WriteAt<uint64_t>(header_size + (8 * 2), next_cap++);
|
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 2), next_cap++);
|
||||||
|
|
||||||
// The next extension pointer is the length of the message.
|
// The next extension pointer is the length of the message.
|
||||||
WriteHeader(bytes, core_size, next_extension);
|
WriteHeader(bytes, offset, core_size, next_extension);
|
||||||
}
|
|
||||||
|
return next_extension;
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
// Generated file - DO NOT MODIFY
|
// Generated file - DO NOT MODIFY
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@ -6,8 +5,6 @@
|
||||||
#include <glacier/buffer/cap_buffer.h>
|
#include <glacier/buffer/cap_buffer.h>
|
||||||
#include <glacier/string/string.h>
|
#include <glacier/string/string.h>
|
||||||
#include <ztypes.h>
|
#include <ztypes.h>
|
||||||
|
|
||||||
|
|
||||||
class OpenFileRequest {
|
class OpenFileRequest {
|
||||||
public:
|
public:
|
||||||
OpenFileRequest() {}
|
OpenFileRequest() {}
|
||||||
|
@ -15,29 +12,20 @@ class OpenFileRequest {
|
||||||
OpenFileRequest(const OpenFileRequest&) = delete;
|
OpenFileRequest(const OpenFileRequest&) = delete;
|
||||||
OpenFileRequest(OpenFileRequest&&) = delete;
|
OpenFileRequest(OpenFileRequest&&) = delete;
|
||||||
|
|
||||||
void ParseFromBytes(const glcr::ByteBuffer&);
|
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset);
|
||||||
void ParseFromBytes(const glcr::ByteBuffer&, const glcr::CapBuffer&);
|
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&);
|
||||||
void SerializeToBytes(glcr::ByteBuffer&);
|
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset);
|
||||||
void SerializeToBytes(glcr::ByteBuffer&, glcr::CapBuffer&);
|
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&);
|
||||||
|
|
||||||
glcr::String path() { return path_; }
|
glcr::String path() { return path_; }
|
||||||
void set_path(glcr::String value) {
|
void set_path(const glcr::String& value) { path_ = value; }
|
||||||
path_ = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t options() { return options_; }
|
uint64_t options() { return options_; }
|
||||||
void set_options(uint64_t value) {
|
void set_options(const uint64_t& value) { options_ = value; }
|
||||||
options_ = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
glcr::String path_;
|
glcr::String path_;
|
||||||
|
|
||||||
uint64_t options_;
|
uint64_t options_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class File {
|
class File {
|
||||||
public:
|
public:
|
||||||
File() {}
|
File() {}
|
||||||
|
@ -45,32 +33,20 @@ class File {
|
||||||
File(const File&) = delete;
|
File(const File&) = delete;
|
||||||
File(File&&) = delete;
|
File(File&&) = delete;
|
||||||
|
|
||||||
void ParseFromBytes(const glcr::ByteBuffer&);
|
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset);
|
||||||
void ParseFromBytes(const glcr::ByteBuffer&, const glcr::CapBuffer&);
|
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&);
|
||||||
void SerializeToBytes(glcr::ByteBuffer&);
|
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset);
|
||||||
void SerializeToBytes(glcr::ByteBuffer&, glcr::CapBuffer&);
|
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&);
|
||||||
|
|
||||||
glcr::String path() { return path_; }
|
glcr::String path() { return path_; }
|
||||||
void set_path(glcr::String value) {
|
void set_path(const glcr::String& value) { path_ = value; }
|
||||||
path_ = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t attrs() { return attrs_; }
|
uint64_t attrs() { return attrs_; }
|
||||||
void set_attrs(uint64_t value) {
|
void set_attrs(const uint64_t& value) { attrs_ = value; }
|
||||||
attrs_ = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
z_cap_t mem_cap() { return mem_cap_; }
|
z_cap_t mem_cap() { return mem_cap_; }
|
||||||
void set_mem_cap(z_cap_t value) {
|
void set_mem_cap(const z_cap_t& value) { mem_cap_ = value; }
|
||||||
mem_cap_ = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
glcr::String path_;
|
glcr::String path_;
|
||||||
|
|
||||||
uint64_t attrs_;
|
uint64_t attrs_;
|
||||||
|
|
||||||
z_cap_t mem_cap_;
|
z_cap_t mem_cap_;
|
||||||
|
|
||||||
};
|
};
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Generated file - DO NOT MODIFY
|
||||||
|
#include "example.yunq.client.h"
|
||||||
|
|
||||||
|
#include <glacier/buffer/byte_buffer.h>
|
||||||
|
#include <glacier/buffer/cap_buffer.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
glcr::ErrorCode open(const OpenFileRequest& request, File& response) {
|
||||||
|
uint64_t buffer_size = 0x1000;
|
||||||
|
// FIXME: Maybe raise this limit.
|
||||||
|
uint64_t cap_size = 100;
|
||||||
|
glcr::ByteBuffer buffer(buffer_size);
|
||||||
|
glcr::CapBuffer caps(cap_size);
|
||||||
|
|
||||||
|
const uint32_t kSentinel = 0xBEEFDEAD;
|
||||||
|
buffer.WriteAt<uint32_t>(0, kSentinel);
|
||||||
|
buffer.WriteAt<uint64_t>(8, {method_number});
|
||||||
|
|
||||||
|
uint64_t length = request.SerializeToBytes(buffer, /*offset=*/16, caps);
|
||||||
|
buffer.WriteAt<uint32_t>(4, 16 + length);
|
||||||
|
|
||||||
|
z_cap_t reply_port_cap;
|
||||||
|
// FIXME: We need to be able to send capabilities via endpoint call.
|
||||||
|
RET_ERR(ZEndpointSend(endpoint_, 16 + length, buffer.RawPtr()));
|
||||||
|
|
||||||
|
// FIXME: Add a way to zero out the first buffer.
|
||||||
|
glcr::ByteBuffer recv_buffer(buffer_size);
|
||||||
|
glcr::CapBuffer recv_caps(cap_size);
|
||||||
|
RET_ERR(ZReplyPortRecv(reply_port_cap, &buffer_size, recv_buffer.RawPtr(), &cap_size, recv_caps.RawPtr()));
|
||||||
|
|
||||||
|
if (recv_buffer.At<uint32_t>(0) != kSentinel) {
|
||||||
|
return glcr::INVALID_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Response Code.
|
||||||
|
RET_ERR(recv_buffer.At<uint64_t>(8));
|
||||||
|
|
||||||
|
response.ParseFromBytes(recv_buffer, 16, recv_caps);
|
||||||
|
|
||||||
|
return glcr::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Generated File -- DO NOT MODIFY.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mammoth/thread.h>
|
||||||
|
#include <ztypes.h>
|
||||||
|
|
||||||
|
#include "example.yunq.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class VFSServerBase {
|
||||||
|
public:
|
||||||
|
VFSServerBase(z_cap_t VFS_cap) : {}
|
||||||
|
VFSServerBase(const VFSServerBase&) = delete;
|
||||||
|
VFSServerBase(VFSServerBase&&) = delete;
|
||||||
|
|
||||||
|
[[nodiscard]] Thread RunServer();
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] virtual glcr::ErrorCode Handleopen(const OpenFileRequest&, File&) = 0;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
z_cap_t endpoint_;
|
||||||
|
|
||||||
|
friend void VFSServerBaseThreadBootstrap(void*);
|
||||||
|
void ServerThread();
|
||||||
|
|
||||||
|
[[nodiscard]] glcr::ErrorCode HandleRequest(const glcr::ByteBuffer& request, glcr::ByteBuffer& response,
|
||||||
|
glcr::CapBuffer& resp_caps);
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
// Generated file -- DO NOT MODIFY.
|
||||||
|
#include "{{file}}.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const uint64_t header_size = 24; // 4x uint32, 1x uint64
|
||||||
|
|
||||||
|
struct ExtPointer {
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
void CheckHeader(const glcr::ByteBuffer& bytes) {
|
||||||
|
// TODO: Check ident.
|
||||||
|
// TODO: Parse core size.
|
||||||
|
// TODO: Parse extension size.
|
||||||
|
// TODO: Check CRC32
|
||||||
|
// TODO: Parse options.
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteHeader(glcr::ByteBuffer& bytes, uint64_t offset, uint32_t core_size, uint32_t extension_size) {
|
||||||
|
bytes.WriteAt<uint32_t>(offset + 0, 0xDEADBEEF); // TODO: Chose a more unique ident sequence.
|
||||||
|
bytes.WriteAt<uint32_t>(offset + 4, core_size);
|
||||||
|
bytes.WriteAt<uint32_t>(offset + 8, extension_size);
|
||||||
|
bytes.WriteAt<uint32_t>(offset + 12, 0); // TODO: Calculate CRC32.
|
||||||
|
bytes.WriteAt<uint64_t>(offset + 16, 0); // TODO: Add options.
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
{%- for message in messages %}
|
||||||
|
void {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) {
|
||||||
|
CheckHeader(bytes);
|
||||||
|
|
||||||
|
{%- for field in message.fields %}
|
||||||
|
// Parse {{field.name}}.
|
||||||
|
{%- if field.type == Type.U64 %}
|
||||||
|
set_{{field.name}}(bytes.At<uint64_t>(offset + header_size + (8 * {{loop.index0}})));
|
||||||
|
{%- elif field.type == Type.I64 %}
|
||||||
|
set_{{field.name}}(bytes.At<int64_t>(offset + header_size + (8 * {{loop.index0}})));
|
||||||
|
{%- elif field.type == Type.STRING %}
|
||||||
|
auto {{field.name}}_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * {{loop.index0}}));
|
||||||
|
|
||||||
|
set_{{field.name}}(bytes.StringAt(offset + {{field.name}}_pointer.offset, {{field.name}}_pointer.length));
|
||||||
|
{%- elif field.type == Type.CAPABILITY %}
|
||||||
|
// FIXME: Implement in-buffer capabilities for inprocess serialization.
|
||||||
|
set_{{field.name}}(0);
|
||||||
|
{%- else %}
|
||||||
|
// TODO: Unimplemented parsing {{field.type}}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
|
void {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) {
|
||||||
|
CheckHeader(bytes);
|
||||||
|
|
||||||
|
{%- for field in message.fields %}
|
||||||
|
// Parse {{field.name}}.
|
||||||
|
{%- if field.type == Type.U64 %}
|
||||||
|
set_{{field.name}}(bytes.At<uint64_t>(offset + header_size + (8 * {{loop.index0}})));
|
||||||
|
{%- elif field.type == Type.I64 %}
|
||||||
|
set_{{field.name}}(bytes.At<int64_t>(offset + header_size + (8 * {{loop.index0}})));
|
||||||
|
{%- elif field.type == Type.STRING %}
|
||||||
|
auto {{field.name}}_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * {{loop.index0}}));
|
||||||
|
|
||||||
|
set_{{field.name}}(bytes.StringAt(offset + {{field.name}}_pointer.offset, {{field.name}}_pointer.length));
|
||||||
|
{%- elif field.type == Type.CAPABILITY %}
|
||||||
|
uint64_t {{field.name}}_ptr = bytes.At<uint64_t>(offset + header_size + (8 * {{loop.index0}}));
|
||||||
|
|
||||||
|
set_{{field.name}}(caps.At({{field.name}}_ptr));
|
||||||
|
{%- else %}
|
||||||
|
// TODO: Unimplemented parsing {{field.type}}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) {
|
||||||
|
uint32_t next_extension = header_size + 8 * {{ message.fields | length }};
|
||||||
|
const uint32_t core_size = next_extension;
|
||||||
|
|
||||||
|
{%- for field in message.fields %}
|
||||||
|
// Write {{field.name}}.
|
||||||
|
{%- if field.type == Type.U64 %}
|
||||||
|
bytes.WriteAt<uint64_t>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}());
|
||||||
|
{%- elif field.type == Type.I64 %}
|
||||||
|
bytes.WriteAt<int64_t>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}());
|
||||||
|
{%- elif field.type == Type.STRING %}
|
||||||
|
ExtPointer {{field.name}}_ptr{
|
||||||
|
.offset = next_extension,
|
||||||
|
// FIXME: Check downcast of str length.
|
||||||
|
.length = (uint32_t){{field.name}}().length(),
|
||||||
|
};
|
||||||
|
|
||||||
|
bytes.WriteStringAt(offset + next_extension, {{field.name}}());
|
||||||
|
next_extension += {{field.name}}_ptr.length;
|
||||||
|
|
||||||
|
bytes.WriteAt<ExtPointer>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}_ptr);
|
||||||
|
{%- elif field.type == Type.CAPABILITY %}
|
||||||
|
// FIXME: Implement inbuffer capabilities.
|
||||||
|
bytes.WriteAt<uint64_t>(offset + header_size + (8 * {{loop.index0}}), 0);
|
||||||
|
{%- else %}
|
||||||
|
// TODO: Unimplemented serialization {{field.type}}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
// The next extension pointer is the length of the message.
|
||||||
|
WriteHeader(bytes, offset, core_size, next_extension);
|
||||||
|
|
||||||
|
return next_extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) {
|
||||||
|
uint32_t next_extension = header_size + 8 * {{ message.fields | length}};
|
||||||
|
const uint32_t core_size = next_extension;
|
||||||
|
uint64_t next_cap = 0;
|
||||||
|
|
||||||
|
{%- for field in message.fields %}
|
||||||
|
// Write {{field.name}}.
|
||||||
|
{%- if field.type == Type.U64 %}
|
||||||
|
bytes.WriteAt<uint64_t>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}());
|
||||||
|
{%- elif field.type == Type.I64 %}
|
||||||
|
bytes.WriteAt<int64_t>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}());
|
||||||
|
{%- elif field.type == Type.STRING %}
|
||||||
|
ExtPointer {{field.name}}_ptr{
|
||||||
|
.offset = next_extension,
|
||||||
|
// FIXME: Check downcast of str length.
|
||||||
|
.length = (uint32_t){{field.name}}().length(),
|
||||||
|
};
|
||||||
|
|
||||||
|
bytes.WriteStringAt(offset + next_extension, {{field.name}}());
|
||||||
|
next_extension += {{field.name}}_ptr.length;
|
||||||
|
|
||||||
|
bytes.WriteAt<ExtPointer>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}_ptr);
|
||||||
|
{%- elif field.type == Type.CAPABILITY %}
|
||||||
|
caps.WriteAt(next_cap, {{field.name}}());
|
||||||
|
bytes.WriteAt<uint64_t>(offset + header_size + (8 * {{loop.index0}}), next_cap++);
|
||||||
|
{%- else %}
|
||||||
|
// TODO: Unimplemented serialization {{field.type}}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
// The next extension pointer is the length of the message.
|
||||||
|
WriteHeader(bytes, offset, core_size, next_extension);
|
||||||
|
|
||||||
|
return next_extension;
|
||||||
|
}
|
||||||
|
{%- endfor %}
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Generated file - DO NOT MODIFY
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glacier/buffer/byte_buffer.h>
|
||||||
|
#include <glacier/buffer/cap_buffer.h>
|
||||||
|
#include <glacier/string/string.h>
|
||||||
|
#include <ztypes.h>
|
||||||
|
|
||||||
|
|
||||||
|
{%- for message in messages %}
|
||||||
|
class {{message.name}} {
|
||||||
|
public:
|
||||||
|
{{message.name}}() {}
|
||||||
|
// Delete copy and move until implemented.
|
||||||
|
{{message.name}}(const {{message.name}}&) = delete;
|
||||||
|
{{message.name}}({{message.name}}&&) = delete;
|
||||||
|
|
||||||
|
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);
|
||||||
|
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&);
|
||||||
|
|
||||||
|
{%- for field in message.fields %}
|
||||||
|
{{field.cpp_type()}} {{field.name}}() { return {{field.name}}_; }
|
||||||
|
void set_{{field.name}}(const {{field.cpp_type()}}& value) { {{field.name}}_ = value; }
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
private:
|
||||||
|
{%- for field in message.fields %}
|
||||||
|
{{field.cpp_type()}} {{field.name}}_;
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
};
|
||||||
|
{%- endfor %}
|
|
@ -102,11 +102,22 @@ type_str_dict = {
|
||||||
"capability": Type.CAPABILITY,
|
"capability": Type.CAPABILITY,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type_to_cppstr = {
|
||||||
|
Type.U64: "uint64_t",
|
||||||
|
Type.I64: "int64_t",
|
||||||
|
Type.STRING: "glcr::String",
|
||||||
|
Type.CAPABILITY: "z_cap_t",
|
||||||
|
Type.BYTES: "glcr::Vector<uint8_t>"
|
||||||
|
}
|
||||||
|
|
||||||
class Field():
|
class Field():
|
||||||
def __init__(self, fieldtype: Type, name: str):
|
def __init__(self, fieldtype: Type, name: str):
|
||||||
self.type = fieldtype
|
self.type = fieldtype
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
|
def cpp_type(self):
|
||||||
|
return type_to_cppstr[self.type]
|
||||||
|
|
||||||
class Message():
|
class Message():
|
||||||
def __init__(self, name: str, fields: list[Field]):
|
def __init__(self, name: str, fields: list[Field]):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
jinja2==3.1
|
|
@ -0,0 +1,93 @@
|
||||||
|
// Generated file -- DO NOT MODIFY.
|
||||||
|
#include "{{file}}.server.h"
|
||||||
|
|
||||||
|
#include <mammoth/debug.h>
|
||||||
|
#include <zcall.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const uint32_t kSentinel = 0xBEEFDEAD;
|
||||||
|
const uint32_t kHeaderSize = 0x10;
|
||||||
|
|
||||||
|
void WriteError(glcr::ByteBuffer& buffer, glcr::ErrorCode err) {
|
||||||
|
buffer.WriteAt<uint32_t>(0, kSentinel);
|
||||||
|
buffer.WriteAt<uint32_t>(4, kHeaderSize);
|
||||||
|
buffer.WriteAt<uint64_t>(8, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteHeader(glcr::ByteBuffer& buffer, uint64_t message_length) {
|
||||||
|
buffer.WriteAt<uint32_t>(0, kSentinel);
|
||||||
|
buffer.WriteAt<uint32_t>(4, kHeaderSize + message_length);
|
||||||
|
buffer.WriteAt<uint64_t>(8, glcr::OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
{% for interface in interfaces %}
|
||||||
|
void {{interface.name}}ServerBaseThreadBootstrap(void* server_base) {
|
||||||
|
({{interface.name}}ServerBase*)(server_base)->ServerThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread {{interface.name}}::RunServer() {
|
||||||
|
return Thread({{interface.name}}ServerBaseThreadBootstrap, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void {{interface.name}}::ServerThread() {
|
||||||
|
glcr::ByteBuffer recv_buffer(0x1000);
|
||||||
|
glcr::ByteBuffer resp_buffer(0x1000);
|
||||||
|
uint64_t resp_cap_size = 0x10;
|
||||||
|
glcr::CapBuffer resp_cap(resp_cap_size);
|
||||||
|
z_cap_t reply_port_cap;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
uint64_t recv_buf_size = 0x1000;
|
||||||
|
glcr::ErrorCode recv_err = ZEndpointRecv(endpoint_, &recv_buf_size, recv_buffer.RawPtr(), &reply_port_cap);
|
||||||
|
if (recv_err != glcr::OK) {
|
||||||
|
dbgln("Error in receive: %x", recv_err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t resp_length = 0;
|
||||||
|
|
||||||
|
glcr::ErrorCode err = HandlRequest(recv_buffer, resp_buffer, resp_length, resp_cap);
|
||||||
|
if (err != glcr::OK) {
|
||||||
|
WriteError(resp_buffer, err);
|
||||||
|
ZReplyPortSend(reply_port_cap, kHeaderSize, resp_buffer.RawPtr(), 0, nullptr);
|
||||||
|
} else {
|
||||||
|
WriteHeader(resp_buffer, resp_length);
|
||||||
|
ZReplyPortSend(reply_port_cap, resp_length, resp_buffer.RawPtr(), resp_cap.UsedSlots(), resp_cap.RawPtr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
glcr::ErrorCode {{interface.name}}::HandleRequest(const glcr::ByteBuffer& request, glcr::ByteBuffer& response, uint64_t& resp_length
|
||||||
|
glcr::CapBuffer& resp_caps) {
|
||||||
|
if (recv_buffer.At<uint32_t>(0) != kSentinel) {
|
||||||
|
return glcr::INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t method_select = recv_buffer.At<uint64_t>(8);
|
||||||
|
|
||||||
|
switch(method_select) {
|
||||||
|
{%- for method in interface.methods %}
|
||||||
|
case {{loop.index0}}: {
|
||||||
|
{{method.request}} request;
|
||||||
|
{{method.response}} response;
|
||||||
|
|
||||||
|
request.ParseFromBytes(recv_buffer, kHeaderSize);
|
||||||
|
|
||||||
|
RET_ERR(Handle{{method.name}}(request, response));
|
||||||
|
|
||||||
|
resp_length = response.SerializeToBytes(resp_buffer, kHeaderSize, resp_cap);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
{%- endfor %}
|
||||||
|
default: {
|
||||||
|
return glcr::UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return glcr::OK;
|
||||||
|
}
|
||||||
|
{% endfor %}
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Generated File -- DO NOT MODIFY.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mammoth/thread.h>
|
||||||
|
#include <ztypes.h>
|
||||||
|
|
||||||
|
#include "{{file}}.h"
|
||||||
|
|
||||||
|
{% for interface in interfaces %}
|
||||||
|
|
||||||
|
class {{interface.name}}ServerBase {
|
||||||
|
public:
|
||||||
|
{{interface.name}}ServerBase(z_cap_t {{interface.name}}_cap) : {}
|
||||||
|
{{interface.name}}ServerBase(const {{interface.name}}ServerBase&) = delete;
|
||||||
|
{{interface.name}}ServerBase({{interface.name}}ServerBase&&) = delete;
|
||||||
|
|
||||||
|
[[nodiscard]] Thread RunServer();
|
||||||
|
|
||||||
|
{% for method in interface.methods %}
|
||||||
|
[[nodiscard]] virtual glcr::ErrorCode Handle{{method.name}}(const {{method.request}}&, {{method.response}}&) = 0;
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
private:
|
||||||
|
z_cap_t endpoint_;
|
||||||
|
|
||||||
|
friend void {{interface.name}}ServerBaseThreadBootstrap(void*);
|
||||||
|
void ServerThread();
|
||||||
|
|
||||||
|
[[nodiscard]] glcr::ErrorCode HandleRequest(const glcr::ByteBuffer& request, glcr::ByteBuffer& response,
|
||||||
|
glcr::CapBuffer& resp_caps);
|
||||||
|
};
|
||||||
|
|
||||||
|
{% endfor %}
|
40
yunq/yunq.py
40
yunq/yunq.py
|
@ -1,8 +1,10 @@
|
||||||
#! /usr/bin/python
|
#! python3
|
||||||
import os
|
import os
|
||||||
|
import pathlib
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from codegen_message import *
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
from parser import *
|
from parser import *
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -20,11 +22,41 @@ def main():
|
||||||
ast = parser.parse()
|
ast = parser.parse()
|
||||||
type_check(ast)
|
type_check(ast)
|
||||||
|
|
||||||
|
messages = [m for m in ast if type(m) is Message]
|
||||||
|
interfaces = [i for i in ast if type(i) is Interface]
|
||||||
|
|
||||||
|
jinja_env = Environment(loader=FileSystemLoader(pathlib.Path(__file__).parent.resolve()))
|
||||||
|
|
||||||
|
message_header_tmpl = jinja_env.get_template("message.h.jinja")
|
||||||
with open(filename + '.h', mode='w') as f:
|
with open(filename + '.h', mode='w') as f:
|
||||||
f.write(generate_message_header(ast))
|
message_header = message_header_tmpl.render(messages=messages)
|
||||||
|
f.write(message_header)
|
||||||
|
|
||||||
|
message_impl_tmpl = jinja_env.get_template("message.cpp.jinja")
|
||||||
|
message_impl_tmpl.globals['Type'] = Type
|
||||||
with open(filename + '.cpp', mode='w') as f:
|
with open(filename + '.cpp', mode='w') as f:
|
||||||
f.write(generate_message_impl(filename, ast))
|
message_impl = message_impl_tmpl.render(file=filename, messages=messages)
|
||||||
|
f.write(message_impl)
|
||||||
|
|
||||||
|
client_header_tmpl = jinja_env.get_template("client.h.jinja")
|
||||||
|
with open(filename + '.client.h', mode='w') as f:
|
||||||
|
client_header = client_header_tmpl.render(file=filename, interfaces=interfaces)
|
||||||
|
f.write(client_header)
|
||||||
|
|
||||||
|
client_impl_tmpl = jinja_env.get_template("client.cpp.jinja")
|
||||||
|
with open(filename + '.client.cpp', mode='w') as f:
|
||||||
|
client_impl = client_impl_tmpl.render(file=filename, interfaces=interfaces)
|
||||||
|
f.write(client_impl)
|
||||||
|
|
||||||
|
server_header_tmpl = jinja_env.get_template("server.h.jinja")
|
||||||
|
with open(filename + '.server.h', mode='w') as f:
|
||||||
|
server_header = server_header_tmpl.render(file=filename, interfaces=interfaces)
|
||||||
|
f.write(server_header)
|
||||||
|
|
||||||
|
server_impl_tmpl = jinja_env.get_template("server.cpp.jinja")
|
||||||
|
with open(filename + '.server.cpp', mode='w') as f:
|
||||||
|
server_impl = client_impl_tmpl.render(file=filename, interfaces=interfaces)
|
||||||
|
f.write(server_impl)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in New Issue