Skip to content

Commit

Permalink
Add struct member index logic to JSON loader (#188)
Browse files Browse the repository at this point in the history
* Add struct member index parsing to JSON loader

* Add test case

* really looks like a word to me

* Review fix: improve readability
  • Loading branch information
thomas-bc authored Jan 31, 2025
1 parent edef829 commit 87baace
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 3 deletions.
1 change: 1 addition & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ mcternan
MDFILE
memb
millis
misordered
MML
moz
msc
Expand Down
15 changes: 12 additions & 3 deletions src/fprime_gds/common/loaders/json_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,10 @@ def construct_serializable_type(
SerializableType: The constructed serializable type.
"""
struct_members = []
# Note on struct_members: the order of the members list matter when calling construct_type() below.
# It should be ordered by incrementing index which corresponds to the order in the FPP declaration
# The JSON dictionary ordering is not guaranteed, so we use a dict() to sort by index below.
struct_members = {}
for name, member_dict in qualified_type.get("members").items():
member_type_dict = member_dict["type"]
member_type_obj = self.parse_type(member_type_dict)
Expand All @@ -197,11 +200,17 @@ def construct_serializable_type(
member_type_obj.FORMAT if hasattr(member_type_obj, "FORMAT") else "{}"
)
description = member_type_dict.get("annotation", "")
struct_members.append((name, member_type_obj, fmt_str, description))
member_index = member_dict["index"]
if member_index in struct_members:
raise KeyError(
f"Invalid dictionary: Duplicate index {member_index} in serializable type {type_name}"
)
struct_members[member_index] = (name, member_type_obj, fmt_str, description)

# Construct the serializable type with list of members sorted by index
ser_type = SerializableType.construct_type(
type_name,
struct_members,
[struct_members[i] for i in sorted(struct_members.keys())],
)
self.parsed_types[type_name] = ser_type
return ser_type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,38 @@
"dictionarySpecVersion" : "1.0.0"
},
"typeDefinitions" : [
{
"kind" : "struct",
"qualifiedName" : "Ref.TestMisorderedStructIndexes",
"members" : {
"ThisIsOne" : {
"type" : {
"name" : "U32",
"kind" : "integer",
"size" : 32,
"signed" : false
},
"index" : 1
},
"ThisIsZero" : {
"type" : {
"name" : "U32",
"kind" : "integer",
"size" : 32,
"signed" : false
},
"index" : 0
},
"ThisIsTwo" : {
"type" : {
"name" : "Ref.PacketRecvStatus",
"kind" : "qualifiedIdentifier"
},
"index" : 2
}
},
"annotation" : "This type does not exist in Ref and is only used for GDS internal testing"
},
{
"kind" : "struct",
"qualifiedName" : "Ref.PacketStat",
Expand Down
10 changes: 10 additions & 0 deletions test/fprime_gds/common/loaders/test_json_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ def test_construct_serializable_type(loader):
assert ref_choice_pair.MEMBER_LIST[1][2] == "{}"


def test_struct_with_unordered_members(loader):
misordered_member = loader.parse_type(
{"name": "Ref.TestMisorderedStructIndexes", "kind": "qualifiedIdentifier"}
)
assert issubclass(misordered_member, SerializableType)
assert misordered_member.MEMBER_LIST[0][0] == "ThisIsZero"
assert misordered_member.MEMBER_LIST[1][0] == "ThisIsOne"
assert misordered_member.MEMBER_LIST[2][0] == "ThisIsTwo"


def test_construct_primitive_types(loader):
i32_type = loader.parse_type(
{"name": "I32", "kind": "integer", "size": 32, "signed": True}
Expand Down

0 comments on commit 87baace

Please sign in to comment.