Skip to content

Commit

Permalink
[JsonGen/StubGen] Support fixed arrays (rdkcentral#111)
Browse files Browse the repository at this point in the history
* [JsonGen/StubGen] Support fixed arrays

* fix unknown types passthrough
  • Loading branch information
sebaszm authored Aug 8, 2024
1 parent cd40a55 commit 95d9733
Show file tree
Hide file tree
Showing 5 changed files with 278 additions and 97 deletions.
26 changes: 24 additions & 2 deletions JsonGenerator/source/class_emitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,15 @@ def __EmitAssignment(json_obj, other, type, optional_type=False):
else:
_optional_or_opaque = False # invalid @optional...

emit.Line("%s = %s.%s;" % (prop.cpp_name, other, _prop_name + prop.convert_rhs))
if isinstance(prop, JsonArray) and type == "conv" and prop.schema.get("@arraysize"):
emit.Line("%s.Clear();" % prop.cpp_name)
emit.Line("for (uint16_t i = 0; i < %s; i++) {" % (prop.schema.get("@arraysize")))
emit.Indent()
emit.Line("%s.Add() = %s.%s[i];" % (prop.cpp_name, other, _prop_name + prop.convert_rhs))
emit.Unindent()
emit.Line("}")
else:
emit.Line("%s = %s.%s;" % (prop.cpp_name, other, _prop_name + prop.convert_rhs))

if (prop.optional and not prop.default_value) or _optional_or_opaque:
emit.Unindent()
Expand Down Expand Up @@ -340,7 +348,21 @@ def _EmitConversionOperator(json_obj):
emit.Indent()

conv = (prop.convert if prop.convert else "%s = %s")
emit.Line((conv + ";") % ( ("_value." + prop.actual_name), prop.cpp_name))

if isinstance(prop, JsonArray) and prop.schema.get("@arraysize"):
emit.Line("{")
emit.Indent()
emit.Line("uint16_t i = 0;")
emit.Line("auto it = %s.Elements();" % prop.cpp_name)
emit.Line("while ((it.Next() != true) && (i < %s)) {" % prop.schema.get("@arraysize"))
emit.Indent()
emit.Line("%s[i++] = it.Current();" % ("_value." + prop.actual_name))
emit.Unindent()
emit.Line("}")
emit.Unindent()
emit.Line("}")
else:
emit.Line((conv + ";") % ( ("_value." + prop.actual_name), prop.cpp_name))

if (prop.optional and not prop.default_value):
emit.Unindent()
Expand Down
21 changes: 14 additions & 7 deletions JsonGenerator/source/header_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def ResolveTypedef(type, parent=type):

return type.Resolve()

def ConvertType(var, quiet=False, meta=None):
def ConvertType(var, quiet=False, meta=None, no_array=False):
if not meta:
meta = var.meta

Expand All @@ -171,11 +171,12 @@ def ConvertType(var, quiet=False, meta=None):

cppType = var_type.Type()
is_iterator = (isinstance(cppType, CppParser.Class) and cppType.is_iterator)
is_bitmask = "bitmask" in meta.decorators

# Pointers
if var_type.IsPointer() and (is_iterator or (meta.length and meta.length != ["void"])):
if var_type.IsPointer() and (is_iterator or (meta.length and meta.length != ["void"]) or var.array) and not no_array and not is_bitmask:
# Special case for serializing C-style buffers, that will be converted to base64 encoded strings
if isinstance(cppType, CppParser.Integer) and cppType.size == "char":
if isinstance(cppType, CppParser.Integer) and (cppType.size == "char") and ("encode:base64" in meta.decorators):
props = dict()

if meta.maxlength:
Expand All @@ -186,13 +187,19 @@ def ConvertType(var, quiet=False, meta=None):
if "length" in props:
props["@originaltype"] = cppType.type

props["encode"] = cppType.type != "char"
props["encode"] = (cppType.type != "char")

if meta.range:
props["range"] = meta.range

return "string", props if props else None

elif isinstance(cppType, CppParser.Integer) and (cppType.size == "char") and not var.array:
return ["array", { "items": ConvertParameter(var, no_array=True), "length": " ".join(meta.length), "@arraysize": "#bylength" }]

elif isinstance(cppType, (CppParser.Class, CppParser.String, CppParser.Bool, CppParser.Integer, CppParser.Float)) and var.array:
return ["array", { "items": ConvertParameter(var, no_array=True), "@arraysize": var.array }]

# Special case for iterators, that will be converted to JSON arrays
elif is_iterator and len(cppType.args) == 2:
# Take element type from return value of the Current() method
Expand Down Expand Up @@ -319,7 +326,7 @@ def GenerateObject(ctype, was_typdef):
raise CppParseError(p, "%s: undefined type" % " ".join(p.type))
if isinstance(p.type, str):
raise CppParseError(p, "%s: undefined type" % p.type)
elif isinstance(ResolveTypedef(p.type).Type(), CppParser.Class):
elif isinstance(ResolveTypedef(p.type).Type(), CppParser.Class) and not p.array:
_, props = GenerateObject(ResolveTypedef(p.type).Type(), isinstance(p.type.Type(), CppParser.Typedef))
properties[name] = props
properties[name]["type"] = "object"
Expand Down Expand Up @@ -396,8 +403,8 @@ def ExtractExample(var):
else:
return None

def ConvertParameter(var, quiet=False):
jsonType, args = ConvertType(var, quiet)
def ConvertParameter(var, quiet=False, no_array=False):
jsonType, args = ConvertType(var, quiet, no_array=no_array)
properties = {"type": jsonType}

if args != None:
Expand Down
49 changes: 48 additions & 1 deletion JsonGenerator/source/rpc_emitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ def _Invoke(params, response, parent="", repsonse_parent="", const_cast=False, i
for _, [arg, _] in sorted_vars:
length_var_name = arg.schema.get("length")

if isinstance(arg, JsonString) and length_var_name:
if isinstance(arg, (JsonString, JsonArray)) and length_var_name:
for name, [var, type] in sorted_vars:
if name == length_var_name:
if type == "w":
Expand Down Expand Up @@ -785,6 +785,39 @@ def _Invoke(params, response, parent="", repsonse_parent="", const_cast=False, i
initializer = cpp_name if is_readable else ""
emit.Line("%s%s %s{%s};" % (cv_qualifier, arg.items.cpp_native_type, arg.temp_name, initializer))

elif arg.schema.get("@arraysize"):
if "#" in arg.schema.get("@arraysize"):
for name, [var, var_type] in sorted_vars:
if name == arg.flags.length.local_name:
initializer = (parent + var.cpp_name) if "r" in var_type else ""
emit.Line("%s %s{%s};" % (var.cpp_native_type, var.temp_name, initializer))
break

emit.Line("%s* %s{};" % (arg.items.cpp_native_type, arg.items.temp_name))
emit.Line("if (%s != 0) {" % arg.flags.length.temp_name)
emit.Indent()
emit.Line("%s = static_cast<%s*>(ALLOCA(%s));" % (arg.items.temp_name, arg.items.cpp_native_type, arg.flags.length.temp_name))
emit.Line("ASSERT(%s != nullptr);" % arg.items.temp_name)
_len = arg.flags.length.temp_name
else:
emit.Line("%s %s[%s]{};" % (arg.items.cpp_native_type, arg.items.temp_name, arg.schema.get("@arraysize")))
_len = arg.schema.get("@arraysize")
emit.Line("{")
emit.Indent()

if is_readable:
emit.Line("uint16_t i = 0;")
emit.Line("auto it = %s.Elements();" % arg.local_name)
emit.Line("while ((it.Next() != true) && (i < %s)) {" % _len)
emit.Indent()
emit.Line("%s[i++] = it.Current();" % (arg.items.temp_name))
emit.Unindent()
emit.Line("}")

emit.Unindent()
emit.Line("}")
emit.Line()

elif is_json_source:
response_cpp_name = (response_parent + arg.cpp_name) if response_parent else arg.local_name
initializer = ("(%s)" if isinstance(arg, JsonObject) else "{%s}") % (response_cpp_name if is_writeable else cpp_name)
Expand Down Expand Up @@ -968,6 +1001,20 @@ def _Invoke(params, response, parent="", repsonse_parent="", const_cast=False, i
elif arg.items.schema.get("@bitmask"):
emit.Line("%s = %s;" % (cpp_name, _rhs))

elif arg.schema.get("@arraysize"):
if "#" in arg.schema.get("@arraysize"):
_len = arg.flags.length.temp_name
else:
_len = arg.schema.get("@arraysize")

emit.Line("%s.Clear();" % cpp_name)
emit.Line("for (uint16_t i = 0; i < %s; i++) {" % _len)
emit.Indent()
emit.Line("%s.Add() = %s[i];" % (cpp_name, _rhs))
emit.Unindent()
emit.Line("}")
pass

else:
raise RPCEmitterError("unable to serialize a non-iterator array: %s" % arg.json_name)

Expand Down
Loading

0 comments on commit 95d9733

Please sign in to comment.