Skip to content

Commit

Permalink
zcbor.py: Add support for unordered maps in generated code
Browse files Browse the repository at this point in the history
Add support for the --unordered-maps option to zcbor code
which makes use of the zcbor_unordered_maps_*() API in generated code.

Signed-off-by: Øyvind Rønningstad <[email protected]>
  • Loading branch information
oyvindronningstad committed Dec 10, 2024
1 parent 4906c54 commit c41c056
Show file tree
Hide file tree
Showing 14 changed files with 534 additions and 48 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ usage: zcbor code [-h] -c CDDL [--no-prelude] [-v]
-t ENTRY_TYPES [ENTRY_TYPES ...] [-d] [-e] [--time-header]
[--git-sha-header] [-b {32,64}]
[--include-prefix INCLUDE_PREFIX] [-s]
[--file-header FILE_HEADER]
[--file-header FILE_HEADER] [--unordered-maps]
Parse a CDDL file and produce C code that validates and xcodes CBOR.
The output from this script is a C file and a header file. The header file
Expand Down Expand Up @@ -543,6 +543,13 @@ options:
generated files, e.g. copyright. Can be a string or a
path to a file. If interpreted as a path to an
existing file, the file's contents will be used.
--unordered-maps Add support in the generated code for parsing maps
with unknown element order. When enabled, the
generated code will use the zcbor_unordered_map_*()
API to decode data whenever inside a map. zcbor
detects when ZCBOR_MAP_SMART_SEARCH is needed and
enable This places restrictions on the level of
ambiguity allowed between map keys in a map.
```

Expand Down
4 changes: 3 additions & 1 deletion samples/pet/src/pet_decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#error "The type file was generated with a different default_max_qty than this file"
#endif


#define log_result(state, result, func) do { \
if (!result) { \
zcbor_trace_file(state); \
Expand Down Expand Up @@ -62,14 +63,15 @@ int cbor_decode_Pet(
struct Pet *result,
size_t *payload_len_out)
{
zcbor_state_t states[4];
zcbor_state_t states[4 + 0];

struct zcbor_state_init_params params = {
.states = states,
.n_states = sizeof(states) / sizeof(zcbor_state_t),
.payload = payload,
.payload_len = payload_len,
.elem_count = 1,
.flags_bytes = 0.875,
};

int ret = zcbor_entry_func((zcbor_decoder_t *)decode_Pet, (void *)result, &params);
Expand Down
4 changes: 3 additions & 1 deletion samples/pet/src/pet_encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#error "The type file was generated with a different default_max_qty than this file"
#endif


#define log_result(state, result, func) do { \
if (!result) { \
zcbor_trace_file(state); \
Expand Down Expand Up @@ -56,14 +57,15 @@ int cbor_encode_Pet(
const struct Pet *input,
size_t *payload_len_out)
{
zcbor_state_t states[4];
zcbor_state_t states[4 + 0];

struct zcbor_state_init_params params = {
.states = states,
.n_states = sizeof(states) / sizeof(zcbor_state_t),
.payload = payload,
.payload_len = payload_len,
.elem_count = 1,
.flags_bytes = 0.875,
};

int ret = zcbor_entry_func((zcbor_decoder_t *)encode_Pet, (void *)input, &params);
Expand Down
6 changes: 5 additions & 1 deletion src/zcbor_decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,10 @@ bool zcbor_unordered_map_search(zcbor_decoder_t key_decoder, zcbor_state_t *stat
(void)old_flags;
}

if (!should_try_key(state)) {
zcbor_log("Skipping element at index %zu.\n", get_current_index(state, 0));
}

if (should_try_key(state) && try_key(state, key_result, key_decoder)) {
if (!ZCBOR_MANUALLY_PROCESS_ELEM(state)) {
ZCBOR_FAIL_IF(!zcbor_elem_processed(state));
Expand Down Expand Up @@ -1576,8 +1580,8 @@ bool zcbor_multi_decode(size_t min_decode,
*num_decode = i;
state->payload = payload_bak;
state->elem_count = elem_count_bak;
ZCBOR_ERR_IF(i < min_decode, ZCBOR_ERR_ITERATIONS);
zcbor_log("Found %zu elements.\r\n", i);
ZCBOR_ERR_IF(i < min_decode, ZCBOR_ERR_ITERATIONS);
return true;
}
}
Expand Down
14 changes: 6 additions & 8 deletions tests/cases/serial_recovery.cddl
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
; SPDX-License-Identifier: Apache-2.0
;

Member = ("image" => int) /
("data" => bstr) /
("len" => int) /
("off" => int) /
("sha" => bstr) /
(tstr => any)

Upload = {
3*8members: Member
? "image" => uint,
? "len" => uint,
"off" => uint,
? "sha" => bstr,
? "data" => bstr,
? "upgrade" => bool,
}
46 changes: 46 additions & 0 deletions tests/cases/unordered_map.cddl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
;
; Copyright (c) 2023 Nordic Semiconductor ASA
;
; SPDX-License-Identifier: Apache-2.0
;

UnorderedMap1 = {
1 => "one",
2 => "two",
int => bstr,
"foo" => "bar",
bazboz,
*bstr => intlist,
}

bazboz = ("baz" => "boz")
intlist = [*int]

UnorderedMap2 = {
+typeUnion,
"map" => {
?-1 => bstr,
?-2 => bstr,
?bool => int,
}
}

typeUnion = type1 / type2 / typeDefault
type1 = 1 => tstr
type2 = 2 => tstr
typeDefault = int => nil

UnorderedMap3 = {
1*2000 uint => uint,
1*2000 nint => nint,
}

group1 = (
uint => tstr,
nint => bstr,
)
type3 = 3*3group1

UnorderedMap4 = {
3*3group1,
}
1 change: 1 addition & 0 deletions tests/decode/test3_simple/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ set(py_command_serial_recovery
-d
${bit_arg}
--short-names
--unordered-maps

# Testing the --include-prefix option
--include-prefix serial
Expand Down
43 changes: 18 additions & 25 deletions tests/decode/test3_simple/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,19 +487,15 @@ ZTEST(cbor_decode_test3, test_serial1)
zassert_equal(ZCBOR_SUCCESS, ret, "decoding failed: %d.", ret);
zassert_equal(sizeof(serial_rec_input1), decode_len, NULL);

zassert_equal(5, upload.members_count,
"expect 5 members");
zassert_equal(Member_data_c, upload.members[0].members
.Member_choice, "expect data 1st");
zassert_equal(Member_image_c, upload.members[1].members
.Member_choice, "expect image 2nd");
zassert_equal(Member_len_c, upload.members[2].members
.Member_choice, "was %d\r\n", upload.members[2].members
.Member_choice);
zassert_equal(Member_off_c, upload.members[3].members
.Member_choice, "expect off 4th");
zassert_equal(Member_sha_c, upload.members[4].members
.Member_choice, "expect sha 5th");
zassert_true(upload.data_present, NULL);
zassert_equal(0x129, upload.data.data.len, NULL);
zassert_true(upload.image_present, NULL);
zassert_equal(0, upload.image.image, NULL);
zassert_true(upload.len_present, NULL);
zassert_equal(0x3b2c, upload.len.len, NULL);
zassert_equal(0, upload.off, NULL);
zassert_true(upload.sha_present, NULL);
zassert_equal(0x20, upload.sha.sha.len, NULL);
}

ZTEST(cbor_decode_test3, test_serial2)
Expand All @@ -511,18 +507,15 @@ ZTEST(cbor_decode_test3, test_serial2)
zassert_equal(ZCBOR_SUCCESS, ret, "decoding failed: %d.", ret);
zassert_equal(sizeof(serial_rec_input2), decode_len, NULL);

zassert_equal(5, upload.members_count,
"expect 5 members");
zassert_equal(Member_data_c, upload.members[0].members
.Member_choice, "expect data 1st");
zassert_equal(Member_image_c, upload.members[1].members
.Member_choice, "expect image 2nd");
zassert_equal(Member_len_c, upload.members[2].members
.Member_choice, "expect len 3rd");
zassert_equal(Member_off_c, upload.members[3].members
.Member_choice, "expect off 4th");
zassert_equal(Member_sha_c, upload.members[4].members
.Member_choice, "expect sha 5th");
zassert_true(upload.data_present, NULL);
zassert_equal(0x129, upload.data.data.len, NULL);
zassert_true(upload.image_present, NULL);
zassert_equal(0, upload.image.image, NULL);
zassert_true(upload.len_present, NULL);
zassert_equal(0x2fe0, upload.len.len, NULL);
zassert_equal(0, upload.off, NULL);
zassert_true(upload.sha_present, NULL);
zassert_equal(0x20, upload.sha.sha.len, NULL);
}

ZTEST_SUITE(cbor_decode_test3, NULL, NULL, NULL, NULL, NULL);
2 changes: 2 additions & 0 deletions tests/decode/test9_manifest14/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ cmake_minimum_required(VERSION 3.13.1)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(test9_manifest14)
set(MAP_SEARCH_FLAGS ON) # Because of --unordered maps
include(../../cmake/test_template.cmake)

if (NOT MANIFEST)
Expand All @@ -30,6 +31,7 @@ set(py_command
SUIT_Common_Sequence
-d
${bit_arg}
--unordered-maps
)

execute_process(
Expand Down
40 changes: 40 additions & 0 deletions tests/decode/testA_unordered_map/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#
# Copyright (c) 2021 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#

cmake_minimum_required(VERSION 3.13.1)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(test9_manifest14)
set(MAP_SEARCH_FLAGS ON) # Because of --unordered maps
set(MAP_SMART_SEARCH ON)
include(../../cmake/test_template.cmake)

set(py_command
${PYTHON_EXECUTABLE}
${CMAKE_CURRENT_LIST_DIR}/../../../zcbor/zcbor.py
code
-c ${CMAKE_CURRENT_LIST_DIR}/../../cases/unordered_map.cddl
--output-cmake ${PROJECT_BINARY_DIR}/unordered_map.cmake
-t
UnorderedMap1
UnorderedMap2
UnorderedMap3
UnorderedMap4
-d
${bit_arg}
--unordered-maps
)

execute_process(
COMMAND
${py_command}
COMMAND_ERROR_IS_FATAL ANY
)

include(${PROJECT_BINARY_DIR}/unordered_map.cmake)

target_link_libraries(unordered_map PRIVATE zephyr_interface)
target_link_libraries(app PRIVATE unordered_map)
8 changes: 8 additions & 0 deletions tests/decode/testA_unordered_map/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#
# Copyright (c) 2021 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#

CONFIG_ZTEST=y
CONFIG_ZTEST_STACK_SIZE=131072
Loading

0 comments on commit c41c056

Please sign in to comment.