|
- #include <rtosc/subtree-serialize.h>
- #include <rtosc/ports.h>
- #include <rtosc/rtosc.h>
- #include <cstring>
- #include <cassert>
-
-
- using namespace rtosc;
-
- static void emplace_uint32_cpp(uint8_t *buffer, uint32_t d)
- {
- buffer[0] = ((d>>24) & 0xff);
- buffer[1] = ((d>>16) & 0xff);
- buffer[2] = ((d>>8) & 0xff);
- buffer[3] = ((d>>0) & 0xff);
- }
-
- /*
- * Append another message onto a bundle if the space permits it.
- * If insufficient space is available, then zero is returned and the buffer is
- * untouched.
- *
- * If this is useful it may be generalized to rtosc_bundle_append()
- */
- static size_t append_bundle(char *dst, const char *src,
- size_t max_len, size_t dst_len, size_t src_len)
- {
- assert(rtosc_message_length(src,src_len) == src_len);
-
- //Handle Edge case alignment
- //if(rtosc_bundle_elements(dst, dst_len) == 0)
- // dst_len -= 4;
-
-
- if(max_len < dst_len + src_len + 4 || dst_len == 0 || src_len == 0)
- return 0;
- emplace_uint32_cpp((uint8_t*)(dst+dst_len), src_len);
-
- memcpy(dst+dst_len+4, src, src_len);
-
- return dst_len + src_len + 4;
- }
-
- //This object captures the output of any given port by calling it through a no
- //argument message
- //Assuming that the loc field is set correctly the message stored here will be
- //able to be replayed to get an object to a previous state
- class VarCapture : public RtData
- {
- public:
- char buf[128];
- char location[128];
- char msg[128];
- const char *dummy;
- bool success;
-
- VarCapture(void)
- :dummy("/ser\0\0\0\0,\0\0\0")
- {
- memset(buf, 0, sizeof(buf));
- memset(location, 0, sizeof(buf));
- this->loc = location;
- success = false;
- }
-
- const char *capture(const Ports *p, const char *path, void *obj_)
- {
- this->loc = location;
- assert(this->loc == location);
- this->obj = obj_;
- location[0] = '/';
- strcpy(location+1, path);
- success = false;
- size_t len = rtosc_message(msg, 128, path, "");
- (void) len;
- assert(len);
- assert(!strchr(path, ':'));
-
- p->dispatch(msg, *this);
- return success ? buf : NULL;
- }
-
- virtual void reply(const char *path, const char *args, ...)
- {
- assert(!success);
- assert(*path);
- va_list va;
- va_start(va, args);
- size_t len = rtosc_vmessage(buf, 128, path, args, va);
- (void) len;
- assert(len != 0);
- success = true;
- va_end(va);
- }
- virtual void broadcast(const char *msg)
- {
- (void) msg;
- }
- };
-
- struct subtree_args_t
- {
- VarCapture v, vv;
- size_t len;
- char *buffer;
- size_t buffer_size;
- void *object;
- rtosc::Ports *ports;
- };
-
- size_t subtree_serialize(char *buffer, size_t buffer_size,
- void *object, rtosc::Ports *ports)
- {
- (void) object;
- assert(buffer);
- assert(ports);
-
- subtree_args_t args;
- args.v.obj = object;
- args.len = rtosc_bundle(buffer, buffer_size, 0xdeadbeef0a0b0c0dULL, 0);
- args.buffer = buffer;
- args.buffer_size = buffer_size;
- args.object = object;
- args.ports = ports;
-
-
- //TODO FIXME this is not currently RT safe at the moment
- walk_ports(ports, args.v.loc, 128, &args, [](const Port *p, const char *, void *dat) {
- if(p->meta().find("internal") != p->meta().end())
- return;
-
- subtree_args_t *args = (subtree_args_t*) dat;
-
- const char *buf = args->vv.capture(args->ports, args->v.loc+1, args->object);
- if(buf)
- args->len = append_bundle(args->buffer, buf, args->buffer_size, args->len,
- rtosc_message_length(buf, 128));
- });
-
- return args.len;
- }
-
- void subtree_deserialize(char *buffer, size_t buffer_size,
- void *object, rtosc::Ports *ports, RtData &d)
- {
- d.obj = object;
- //simply replay all objects seen here
- for(unsigned i=0; i<rtosc_bundle_elements(buffer, buffer_size); ++i) {
- const char *msg = rtosc_bundle_fetch(buffer, i);
- ports->dispatch(msg+1, d);
- }
- }
|