Anklang 0.3.0-460-gc4ef46ba
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
serialize.cc
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#include "serialize.hh"
3#include "jsonapi.hh"
4#include "utils.hh"
5#include "internal.hh"
6#include <rapidjson/prettywriter.h>
7
8namespace Ase {
9
10// == Writ::InstanceMap ==
11Jsonipc::JsonValue
12Writ::InstanceMap::wrapper_to_json (Wrapper *wrapper, const size_t thisid, Jsonipc::JsonAllocator &allocator)
13{
14 warning ("Ase::Writ: object pointer is not persistent: (%s*) {\"$id\":%d}", wrapper->classname(), thisid);
15 //return Jsonipc::JsonValue(); // null
16 return this->Jsonipc::InstanceMap::wrapper_to_json (wrapper, thisid, allocator);
17}
18
20Writ::InstanceMap::wrapper_from_json (const Jsonipc::JsonValue &value)
21{
22 if (!value.IsNull())
23 warning ("Ase::Writ: non persistent object cannot resolve: %s*", Jsonipc::jsonvalue_to_string (value));
24 //return nullptr;
25 return this->Jsonipc::InstanceMap::wrapper_from_json (value);
26}
27
28// == Writ ==
29Writ::Writ (Flags flags) :
30 root_(*this, std::make_shared<Value> (Value::empty_value)),
31 skip_zero_ (flags & SKIP_ZERO),
32 skip_emptystring_ (flags & SKIP_EMPTYSTRING),
33 relaxed_ (flags & RELAXED),
34 dummy_ (std::make_shared<Value>())
35{}
36
38Writ::dummy ()
39{
40 if (dummy_->index() != Value::NONE)
41 {
42 warning ("invalid Writ::dummy assignment: %s", dummy_->repr());
43 *dummy_ = Value();
44 }
45 return dummy_;
46}
47
48void
49Writ::reset (int mode)
50{
51 assert_return (mode == 1 || mode == 2);
52 in_load_ = mode == 1;
53 in_save_ = mode == 2;
54 root_.value_ = Value::empty_value;
55 linkptrs_.clear();
56 links_.clear();
57 link_counter_ = 8000;
58}
59
61Writ::to_json()
62{
63 Jsonipc::Scope scope (instance_map_);
64 rapidjson::Document document (rapidjson::kNullType);
65 Jsonipc::JsonValue &docroot = document;
66 Jsonipc::JsonAllocator &allocator = document.GetAllocator();
67 docroot = Jsonipc::to_json (root_.value_, allocator); // move semantics!
68 rapidjson::StringBuffer buffer;
69 if (relaxed_)
70 {
71 constexpr unsigned FLAGS = rapidjson::kWriteNanAndInfFlag;
72 rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<>, rapidjson::UTF8<>, rapidjson::CrtAllocator, FLAGS> writer (buffer);
73 writer.SetIndent (' ', 2);
74 writer.SetFormatOptions (rapidjson::kFormatSingleLineArray);
75 document.Accept (writer);
76 }
77 else
78 {
79 rapidjson::Writer<rapidjson::StringBuffer> writer (buffer);
80 document.Accept (writer);
81 }
82 const String output { buffer.GetString(), buffer.GetSize() };
83 return output;
84}
85
86bool
87Writ::from_json (const String &jsonstring)
88{
89 reset (1);
90 Jsonipc::Scope scope (instance_map_);
91 rapidjson::Document document;
92 Jsonipc::JsonValue &docroot = document;
93 constexpr unsigned PARSE_FLAGS =
94 rapidjson::kParseFullPrecisionFlag |
95 rapidjson::kParseCommentsFlag |
96 rapidjson::kParseTrailingCommasFlag |
97 rapidjson::kParseNanAndInfFlag |
98 rapidjson::kParseEscapedApostropheFlag;
99 document.Parse<PARSE_FLAGS> (jsonstring.data(), jsonstring.size());
100 if (document.HasParseError())
101 {
102 // printerr ("%s: JSON-ERROR: %s\n", __func__, jsonstring);
103 return false;
104 }
105 root_.value_ = Jsonipc::from_json<Value> (docroot);
106 return true;
107}
108
109void
110Writ::blank_enum (const String &enumname)
111{
112 warning ("%s: serialization of enum type without values: %s", "Writ::blank_enum", enumname);
113}
114
115void
116Writ::not_serializable (const String &classname)
117{
118 warning ("%s: type not registered as Jsonipc::Serializable<>: %s", "Writ::not_serializable", classname);
119}
120
122bool
123Writ::typedata_is_loadable (const StringS &typedata, const std::string &fieldname)
124{
125 return_unless (!typedata.empty() && !fieldname.empty(), true); // avoid constraining unknown fields
126 return true; // TODO: check Property hints here
127}
128
130bool
131Writ::typedata_is_storable (const StringS &typedata, const std::string &fieldname)
132{
133 return_unless (!typedata.empty() && !fieldname.empty(), true); // avoid constraining unknown fields
134 return true; // TODO: check Property hints here
135}
136
138bool
139Writ::typedata_find_minimum (const StringS &typedata, const std::string &fieldname, long double *limit)
140{
141 return_unless (!typedata.empty() && !fieldname.empty(), false); // avoid constraining unknown fields
142 return false; // TODO: check Property hints here
143}
144
146bool
147Writ::typedata_find_maximum (const StringS &typedata, const std::string &fieldname, long double *limit)
148{
149 return_unless (!typedata.empty() && !fieldname.empty(), false); // avoid constraining unknown fields
150 return false; // TODO: check Property hints here
151}
152
154void
155Writ::prepare_link (Serializable &serializable, ValueP valuep)
156{
158 assert_return (valuep);
159 for (LinkEntry &e : links_)
160 if (e.sp == &serializable)
161 {
162 if (e.value)
163 warning ("Ase::Writ: duplicate serialization of: (%s)%p", Jsonipc::rtti_typename (serializable), &serializable);
164 e.value = valuep;
165 return;
166 }
167 links_.push_back ({ valuep, &serializable, 0 });
168}
169
171int64
172Writ::use_link (Serializable &serializable)
173{
174 assert_return (in_save(), 0);
175 for (LinkEntry &e : links_)
176 if (e.sp == &serializable)
177 {
178 if (!e.id)
179 e.id = ++link_counter_;
180 return e.id;
181 }
182 links_.push_back ({ nullptr, &serializable, ++link_counter_ });
183 return links_.back().id;
184}
185
186static const char *const ase_linkid = "\u0012.ID"; // DC2 - http://fileformats.archiveteam.org/wiki/C0_controls
187
189void
190Writ::insert_links ()
191{
193 for (LinkEntry &e : links_)
194 if (e.id)
195 {
196 if (e.value && e.value->index() == Value::RECORD)
197 {
198 ValueR &rec = std::get<ValueR> (*e.value);
199 rec.insert (rec.begin(), { ase_linkid, e.id });
200 }
201 else
202 warning ("Ase::Writ: missing serialization of: (%s)%p", Jsonipc::rtti_typename (*e.sp), e.sp);
203 }
204}
205
207void
208Writ::collect_link (int64 id, Serializable &serializable)
209{
211 links_.push_back ({ nullptr, &serializable, id });
212}
213
216Writ::resolve_link (int64 id)
217{
218 assert_return (in_load(), nullptr);
219 for (LinkEntry &e : links_)
220 if (id == e.id)
221 return e.sp;
222 return nullptr;
223}
224
226void
227Writ::assign_links ()
228{
230 for (LinkPtr &e : linkptrs_)
231 {
232 Serializable *serializable = resolve_link (e.id);
233 if (serializable)
234 *e.spp = serializable;
235 else
236 warning ("Ase::Writ: failed to resolve serialization link: %d", e.id);
237 }
238 linkptrs_.clear();
239}
240
241// == WritNode ==
242WritNode::WritNode (Writ &writ, ValueP vp) :
243 writ_ (writ), valuep_ (vp), value_ (*vp)
244{
245 assert_return (valuep_ != nullptr);
246}
247
250WritNode::recfield (const String &fieldname, bool front)
251{
252 if (in_save())
253 {
254 assert_return (value_.index() == Value::RECORD, { writ_, dummy() });
255 ValueR &rec = std::get<ValueR> (value_);
256 return WritNode { writ_, rec.valuep (fieldname, front) };
257 }
258 if (in_load() && value_.index() == Value::RECORD)
259 {
260 ValueR &rec = std::get<ValueR> (value_);
261 ValueP vp = rec.peek (fieldname);
262 if (vp)
263 return WritNode { writ_, vp };
264 }
265 return WritNode { writ_, dummy() };
266}
267
271{
272 WritNodeS nodes;
273 if (in_load())
274 {
275 const ValueS &values = value_.as_array();
276 nodes.reserve (values.size());
277 for (auto &valp : values)
278 nodes.push_back ({ writ_, valp });
279 }
280 return nodes;
281}
282
286{
287 if (in_save())
288 {
289 if (value_.index() == Value::NONE)
290 value_ = ValueS::empty_array;
291 if (value_.index() == Value::ARRAY)
292 {
293 ValueS &array = std::get<ValueS> (value_);
294 array.push_back (Value());
295 return { writ_, array.back() };
296 }
297 }
298 const WritNode fallback { writ_, dummy() };
299 assert_return (in_save(), fallback);
300 assert_return (value_.index() == Value::ARRAY, fallback);
301 return fallback;
302}
303
305bool
307{
308 if (in_save())
309 {
310 if (*l.spp_)
311 {
312 const int64 linkid = writ_.use_link (**l.spp_);
313 value_ = linkid;
314 }
315 else
316 value_ = Value(); // null
317 return true;
318 }
319 if (in_load())
320 {
321 const int64 linkid = value_.as_int();
322 *l.spp_ = nullptr;
323 if (linkid)
324 writ_.linkptrs_.push_back ({ l.spp_, linkid });
325 return true;
326 }
327 return false;
328}
329
330bool
331WritNode::serialize (Serializable &serializable)
332{
333 if (in_save())
334 {
335 assert_return (value_.index() == Value::NONE, false);
336 value_ = ValueR::empty_record;
337 writ_.prepare_link (serializable, valuep_);
338 serializable.serialize (*this);
339 }
340 if (in_load())
341 {
342 if (value_.index() == Value::RECORD)
343 {
344 const int64 linkid = (*this)[ase_linkid].as_int();
345 if (linkid)
346 writ_.collect_link (linkid, serializable);
347 }
348 serializable.serialize (*this);
349 }
350 return true;
351}
352
353void
355{
356 const bool purge_emptystring = skip_emptystring(), purge_zero = skip_zero();
357 return_unless (purge_emptystring || purge_zero);
358 value_.filter ([purge_emptystring,purge_zero] (const ValueField &field) {
359 return_unless (field.value, false);
360 if (purge_emptystring && field.value->index() == Value::STRING && std::get<String> (*field.value) == "")
361 return true;
362 if (purge_zero && field.value->index() == Value::INT64 && std::get<int64> (*field.value) == 0)
363 return true;
364 if (purge_zero && field.value->index() == Value::DOUBLE && std::get<double> (*field.value) == 0)
365 return true;
366 return false;
367 });
368}
369
370// == WritLink ==
371WritLink::WritLink (Serializable **spp) :
372 spp_(spp)
373{
374 assert_return (spp != nullptr);
375}
376
377// == Serializable ==
378void
380{
381 // present, so it can be chained to
382}
383
384} // Ase
385
386#include "api.hh"
387#include "testing.hh"
388
389namespace { // Anon
390using namespace Ase;
391
392struct Simple { int i = 0; float f = 0; String s; };
393static void
394serialize (Simple &simple, WritNode &xs)
395{
396 xs["i"] & simple.i;
397 xs["f"] & simple.f;
398 xs["s"] & simple.s;
399}
400
401struct SBase : Serializable {
402 String hi;
403 double d;
404 int32 i;
405 bool b0, b1;
406 Error e = Error (0);
407 std::vector<char> chars;
409 ServerP serverp;
410 void
411 fill()
412 {
413 hi = "hi";
414 d = 17.5;
415 i = 32;
416 b0 = false;
417 b1 = true;
418 e = Error::IO;
419 serverp = Server::instancep();
420 chars.push_back ('A');
421 chars.push_back ('B');
422 chars.push_back ('C');
423 tf = { .name = "NAME", .type = "TYPE", .offset = -1234567, .length = 987654321 };
424 }
425 void
426 serialize (WritNode &xs) override
427 {
428 xs["b0"] & b0;
429 xs["b1"] & b1;
430 xs["i"] & i;
431 xs["d"] & d;
432 xs["s"] & hi;
433 xs["e"] & e;
434 xs["chars"] & chars;
435 xs["tf"] & tf;
436 // xs["server"] & serverp; // <- pointer is not persistent
437 }
438};
439
440template<typename T> static T via_json (const T &v) { return json_parse<T> (json_stringify (v)); }
441
442TEST_INTEGRITY (ase_serialize);
443static void
444ase_serialize()
445{
446 // Basics
447 TASSERT (false == via_json (false)); // BOOL
448 TASSERT (true == via_json (true));
449 TASSERT (-2 == via_json (-2)); // INT64
450 TASSERT (+3.5 == via_json (+3.5)); // DOUBLE
451 TASSERT ("" == via_json (String (""))); // STRING
452 TASSERT ("x123y" == via_json (String ("x123y")));
453 TASSERT (Error::PERMS == via_json (Error::PERMS)); // ENUM
454 { // ARRAY
455 std::vector<double> floats = { 1e3, 0, -9, +0.75, +6, -0.5, 32767 }, floats2 = floats;
456 TASSERT (floats == via_json (floats2));
457 }
458 { // RECORD
459 using namespace MakeIcon;
460 Choice choice = { "grump", "¿"_uc, "Grump", "A flashy Grump", "Notice", "Warn" }, choice2 = via_json (choice);
461 TASSERT (choice.ident == choice2.ident && choice.icon == choice2.icon && choice.label == choice2.label &&
462 choice.blurb == choice2.blurb && choice.notice == choice2.notice && choice.warning == choice2.warning);
463 }
464 { // tuple
465 using Tuple = std::tuple<String,long,double>;
466 Tuple tuple = { "TUPLE", -618033988, 1.6180339887498948482 };
467 Tuple u = via_json (tuple);
468 TASSERT (std::get<0> (u) == "TUPLE" && std::get<long> (u) == -618033988);
469 TASSERT (fabs (std::get<2> (u) - 1.6180339887498948482) < 1e-16);
470 }
471 { // serialize (O&, WritNode&)
472 Simple simple { 7, -3.14159265358979, "SIMPLE" };
473 auto s2 = via_json (simple);
474 TASSERT (s2.i == 7 && fabs (s2.f - -3.14159265358979) < 1e-7 && s2.s == "SIMPLE");
475 }
476 { // Json types
477 std::string s;
478 bool b;
479 s = json_stringify (true); TASSERT (s == "true");
480 TASSERT (json_parse (s, b) && true == b);
481 double d;
482 s = json_stringify (-0.17); TASSERT (s == "-0.17");
483 TASSERT (json_parse (s, d) && -0.17 == d);
484 int i;
485 s = json_stringify (32768); TASSERT (s == "32768");
486 TASSERT (json_parse (s, i) && 32768 == i);
487 Error e;
488 s = json_stringify (Ase::Error::IO); TASSERT (s == "\"Ase.Error.IO\"");
489 TASSERT (json_parse (s, e) && Error::IO == e);
490 String str;
491 s = json_stringify (String ("STRing")); TASSERT (s == "\"STRing\"");
492 TASSERT (json_parse (s, str) && "STRing" == str);
493 Value val;
494 s = json_stringify (Value (0.5)); TASSERT (s == "0.5");
495 TASSERT (json_parse (s, val) && Value (0.5) == val);
496 ValueS vs;
497 s = json_stringify (ValueS ({ true, 5, "HI" })); TASSERT (s == "[true,5,\"HI\"]");
498 TASSERT (json_parse (s, vs) && ValueS ({ true, 5, "HI" }) == vs);
499 ValueR vr;
500 s = json_stringify (ValueR ({ {"a", 1}, {"b", "B"} })); TASSERT (s == "{\"a\":1,\"b\":\"B\"}");
501 TASSERT (json_parse (s, vr) && ValueR ({ {"a", 1}, {"b", "B"} }) == vr);
502 }
503 { // Jsonipc::Serializable<>
504 struct Test1 {
505 int i; std::string t;
506 bool operator== (const Test1 &o) const { return i == o.i && t == o.t; }
507 };
509 test1 .set ("i", &Test1::i) .set ("t", &Test1::t) ;
510 Test1 t1;
511 String s = json_stringify (Test1 ({ 256, "tree" })); TASSERT (s == "{\"i\":256,\"t\":\"tree\"}");
512 TASSERT (json_parse (s, t1) && Test1 ({ 256, "tree" }) == t1);
513 struct Test2 {
514 int i;
515 Test1 t1;
516 bool operator== (const Test2 &o) const {
517 return i == o.i && t1 == o.t1 && server == o.server && serverp == o.serverp;
518 }
519 Server *server = nullptr; // not-persistent
520 ServerP serverp; // not-persistent
521 };
523 test2
524 .set ("i", &Test2::i)
525 .set ("t1", &Test2::t1)
526 .set ("server", &Test2::server) // <- pointer is not persistent
527 // .set ("serverp", &Test2::serverp) // <- pointer is not persistent
528 ;
529 Test2 t2, t2orig = Test2 ({ 777, { 9, "nine" }, });
530 s = json_stringify (Test2 (t2orig));
531 TASSERT (json_parse (s, t2));
532 TASSERT (json_parse (s, t2) && t2 == t2orig);
533 TASSERT (s == R"'''({"i":777,"server":null,"t1":{"i":9,"t":"nine"}})'''");
534 }
535 { // Ase::Serializable derived classes
536 SBase sbase1;
537 sbase1.fill();
538 const String json1 = json_stringify (sbase1);
539 // printerr ("SBase1: %s\n", json1);
540 SBase sbase2;
541 json_parse (json1, sbase2);
542 TASSERT (sbase1.chars == sbase2.chars && sbase1.d == sbase2.d && sbase1.e == sbase2.e);
543 const String json2 = json_stringify (sbase2);
544 // printerr ("SBase2: %s\n", json2);
545 TASSERT (json1 == json2);
546 }
547}
548
549// Ase::Serializable hierarchy test
550struct FrobnicatorBase : public virtual Serializable {
551 uint32_t flags_ = 0x01020304;
552protected:
553 void
554 serialize (WritNode &xs) override
555 {
556 xs["flags"] & flags_;
557 }
558};
559struct FrobnicatorSpecial : public FrobnicatorBase {
560 String kind_;
561 float factor_ = 0;
562 int64 state_ = 0;
563 explicit FrobnicatorSpecial (const String &k) : kind_ (k)
564 {
565 TASSERT (kind_ == "K321" || kind_ == "Special");
566 }
567protected:
568 void
569 serialize (WritNode &xs) override
570 {
571 // serialize *constructor* value, see caller/creator
572 xs["kind"] & kind_;
573 // chaining for base class fields
574 FrobnicatorBase::serialize (xs);
575 // avoid saving defaults according to Writ config
576 if (!xs.skip_emptystring() || state_)
577 xs["state"] & this->state_;
578 if (!xs.skip_zero() || factor_ != 0)
579 xs["factor"] & factor_;
580 }
581};
582using FrobnicatorSpecialP = std::shared_ptr<FrobnicatorSpecial>;
583struct FrobnicatorImpl : public FrobnicatorBase {
584 String kind_;
585 bool yesno_ = 0;
586 Error error_ = {};
587 FrobnicatorSpecialP special_;
590 std::vector<int> nums_;
591 Serializable *sibling_ = nullptr;
592 explicit FrobnicatorImpl (const String &t = "") : kind_ (t) {}
593 ~FrobnicatorImpl()
594 {
595 for (auto *c : children_)
596 delete c;
597 }
599 create_lane (const String &kind)
600 {
601 Serializable *c;
602 if (kind == "Special")
603 c = new FrobnicatorSpecial (kind);
604 else
605 c = new FrobnicatorImpl (kind);
606 return *children_.emplace_back (c);
607 }
608 void
609 populate (bool extended = false)
610 {
611 if (extended)
612 {
613 special_ = std::make_shared<FrobnicatorSpecial> ("K321");
614 special_->flags_ = 321;
615 }
616 nums_ = { 1, 2, 3 };
617 if (extended)
618 matrix_ = { { 9, 8, 7 }, { 6, 5, 4 }, };
619 error_ = Error::NO_MEMORY;
620 }
621protected:
622 void
623 serialize (WritNode &xs) override
624 {
625 // always skips empty default
626 if (xs.in_load() || !kind_.empty())
627 xs["kind"] & kind_;
628 // chaining for base class fields
629 FrobnicatorBase::serialize (xs);
630 // flat arrays
631 xs["nums"] & nums_;
632 // nested arrays
633 xs["matrix"] & matrix_;
634 // conditional serialization
635 if (kind_ == "")
636 xs["error"] & error_;
637 // nested object, maybe null
638 if (xs.loadable ("special"))
639 special_ = std::make_shared<FrobnicatorSpecial> (xs["special"]["kind"].as_string());
640 if (special_)
641 xs["special"] & *special_;
642 // saving children
643 if (xs.in_save()) // children_ in_save
644 for (auto &childp : children_)
645 {
646 WritNode xc = xs["tracks"].push();
647 xc & *childp;
648 }
649 // loading children
650 if (xs.in_load()) // children_ in_load
651 for (auto &xc : xs["tracks"].to_nodes())
652 { // parses child constructor arg on the fly
653 Serializable &child = create_lane (xc["kind"].as_string());
654 xc & child;
655 }
656 // the `sibling_` is assigned at the *end* of the in_load serialization phase
657 xs["sibling"] & WritLink (&sibling_);
658 // serialization through alias
659 String yn = yesno_ ? "yes" : "no";
660 xs["Q?"] & yn;
661 if (xs.in_load() && xs.has ("Q?"))
662 yesno_ = yn == "yes";
663 }
664};
665
666TEST_INTEGRITY (test_serializable_hierarchy);
667static void
668test_serializable_hierarchy()
669{
670 const bool V = 0;
671 String streamtext1;
672 {
673 FrobnicatorImpl prjct;
674 prjct.flags_ = 1717;
675 prjct.populate (true);
676 TASSERT (prjct.children_.size() == 0);
677 auto &nidi = prjct.create_lane ("Nidi");
678 dynamic_cast<FrobnicatorBase*> (&nidi)->flags_ = 0x02020202;
679 prjct.sibling_ = &prjct.create_lane ("Odio");
680 FrobnicatorImpl *fimpl = dynamic_cast<FrobnicatorImpl*> (prjct.sibling_);
681 fimpl->populate (false);
682 fimpl->yesno_ = true;
683 TASSERT (prjct.children_.size() == 2);
684 FrobnicatorSpecial *special = dynamic_cast<FrobnicatorSpecial*> (&prjct.create_lane ("Special"));
685 special->flags_ = 0xeaeaeaea;
686 special->factor_ = 2.5;
687 special->state_ = -17;
688 TASSERT (prjct.children_.size() == 3);
689 streamtext1 = json_stringify (prjct, Writ::RELAXED);
690 TASSERT (prjct.sibling_ && fimpl && (fimpl->nums_ == std::vector<int> { 1, 2, 3 }));
691 }
692 if (V)
693 printerr ("%s\n", streamtext1);
694 String streamtext2;
695 {
696 FrobnicatorImpl prjct;
697 const bool success = json_parse (streamtext1, prjct);
698 TASSERT (success);
699 TASSERT (prjct.children_.size() > 0 && dynamic_cast<FrobnicatorImpl*> (prjct.children_[0])->kind_ == "Nidi");
700 TASSERT (prjct.children_.size() > 1 && dynamic_cast<FrobnicatorImpl*> (prjct.children_[1])->kind_ == "Odio");
701 TASSERT (prjct.children_.size() > 2 && dynamic_cast<FrobnicatorSpecial*> (prjct.children_[2])->kind_ == "Special");
702 streamtext2 = json_stringify (prjct, Writ::RELAXED);
703 FrobnicatorImpl *fimpl = dynamic_cast<FrobnicatorImpl*> (prjct.sibling_);
704 TASSERT (prjct.sibling_ && fimpl && (fimpl->nums_ == std::vector<int> { 1, 2, 3 }));
705 }
706 if (V)
707 printerr ("%s\n", streamtext2);
708 TASSERT (streamtext1 == streamtext2);
709}
710
711} // Anon
T back(T... args)
T begin(T... args)
Interface for serializable objects with Reflink support.
Definition defs.hh:97
virtual void serialize(WritNode &xs)=0
Serialize members and childern.
Definition serialize.cc:379
Central singleton, serves as API entry point.
Definition api.hh:400
static ServerP instancep()
Retrieve global Server instance as std::shared_ptr.
Definition server.cc:155
One entry in a Writ serialization document.
Definition serialize.hh:24
bool skip_emptystring() const
Omit empty strings during in_save()
Definition serialize.hh:187
WritNode push()
Append new WritNode for serializing arrays during in_save().
Definition serialize.cc:285
bool in_load() const
Return true during deserialization.
Definition serialize.hh:175
bool skip_zero() const
Omit zero integers or floats during in_save()
Definition serialize.hh:193
bool in_save() const
Return true during serialization.
Definition serialize.hh:181
WritNodeS to_nodes()
Create std::vector<WritNode> for serialized arrays during in_load().
Definition serialize.cc:270
void purge_value()
Clean up defaults in Value.
Definition serialize.cc:354
bool loadable(const String &key) const
True if in_load() && has (key).
Definition serialize.hh:211
bool operator&(T &v)
Serialization operator.
Definition serialize.hh:218
Document containing all information needed to serialize and deserialize a Value.
Definition serialize.hh:71
bool in_save() const
Return true during serialization.
Definition serialize.hh:102
static bool typedata_find_minimum(const StringS &typedata, const std::string &fieldname, long double *limit)
Find the minimum value for field of typedata.
Definition serialize.cc:139
static bool typedata_find_maximum(const StringS &typedata, const std::string &fieldname, long double *limit)
Find the maximum value for field of typedata.
Definition serialize.cc:147
static bool typedata_is_loadable(const StringS &typedata, const String &fieldname)
Check for the writable and storage flags in the hints field of typedata.
Definition serialize.cc:123
bool in_load() const
Return true during deserialization.
Definition serialize.hh:101
static bool typedata_is_storable(const StringS &typedata, const String &fieldname)
Check for the readable and storage flags in the hints field of typedata.
Definition serialize.cc:131
Keep track of temporary instances during IpcDispatcher::dispatch_message().
Definition jsonipc.hh:163
T clear(T... args)
T data(T... args)
T empty(T... args)
fabs
T fill(T... args)
T insert(T... args)
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
Definition internal.hh:29
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
Definition internal.hh:71
#define TEST_INTEGRITY(FUNC)
Register func as an integrity test.
Definition internal.hh:77
T make_shared(T... args)
Flags
Flags for allocator behavior.
Definition loft.hh:13
The Anklang C++ API namespace.
Definition api.hh:9
int32_t int32
A 32-bit signed integer.
Definition cxxaux.hh:28
String name
Names like "bpm", etc.
Definition api.hh:114
bool json_parse(const String &jsonstring, T &target)
Parse a well formed JSON string and assign contents to target.
Definition serialize.hh:538
int64_t int64
A 64-bit unsigned integer, use PRI*64 in format strings.
Definition cxxaux.hh:29
Error
Enum representing Error states.
Definition api.hh:22
String json_stringify(const T &source, Writ::Flags flags=Writ::Flags(0))
Create JSON string from source.
Definition serialize.hh:530
Telemetry segment location.
Definition api.hh:113
T push_back(T... args)
T reserve(T... args)
T size(T... args)
typedef uint32_t
Representation of one possible choice for selection properties.
Definition api.hh:96
String warning
Potential problem indicator.
Definition api.hh:102
String ident
Identifier used for serialization (may be derived from untranslated label).
Definition api.hh:97
String icon
Icon (64x64 pixels) or unicode symbol (possibly wide).
Definition api.hh:98
String notice
Additional information of interest.
Definition api.hh:101
String blurb
Short description for overviews.
Definition api.hh:100
String label
Preferred user interface name.
Definition api.hh:99
Value type used to interface with various property types.
Definition value.hh:54
int64 as_int() const
Convert Value to int64 or return 0.
Definition value.cc:59
void filter(const std::function< bool(const ValueField &)> &pred)
Recursively purge/remove RECORD elements iff to pred (recordfield) == true.
Definition value.cc:262
const ValueS & as_array() const
Retrive a non-empty array if Value contains a non-empty array.
Definition value.cc:135
Jsonipc wrapper type for objects that support field-wise serialization to/from JSON.
Definition jsonipc.hh:1185
Serializable & set(const char *name, A attribute)
Add a member object pointer.
Definition jsonipc.hh:1195
#define TASSERT(cond)
Unconditional test assertion, enters breakpoint if not fullfilled.
Definition testing.hh:24
yn