diff --git a/bindings/c/include/molecule_reader.h b/bindings/c/include/molecule_reader.h index c647f0b..f9d8fba 100644 --- a/bindings/c/include/molecule_reader.h +++ b/bindings/c/include/molecule_reader.h @@ -235,6 +235,17 @@ MOLECULE_API_DECORATOR mol_seg_t mol_fixvec_slice_raw_bytes(const mol_seg_t *inp return seg; } +// Check if a segment(`part`) is contained by `total` +MOLECULE_API_DECORATOR bool mol_contained_by(const mol_seg_t *part, const mol_seg_t* total) { + if (part->ptr < total->ptr) { + return MOL_ERR_OFFSET; + } + if ((part->ptr + part->size) > (total->ptr + total->size)) { + return MOL_ERR_OFFSET; + } + return MOL_OK; +} + /* * Undef macros which are internal use only. */ diff --git a/fuzzing/.gitignore b/fuzzing/.gitignore new file mode 100644 index 0000000..a092511 --- /dev/null +++ b/fuzzing/.gitignore @@ -0,0 +1,3 @@ +target +corpus +artifacts diff --git a/fuzzing/c/.gitignore b/fuzzing/c/.gitignore new file mode 100644 index 0000000..7fb028d --- /dev/null +++ b/fuzzing/c/.gitignore @@ -0,0 +1,7 @@ +fuzzer +coverage +fuzz-*.log +crash-* +*.profraw +coverage_dir +manually-gen \ No newline at end of file diff --git a/fuzzing/c/Makefile b/fuzzing/c/Makefile new file mode 100644 index 0000000..5bc02f3 --- /dev/null +++ b/fuzzing/c/Makefile @@ -0,0 +1,53 @@ + +NPROC?=$(shell nproc) +CC=clang-16 +LLVM_PROFDATA=llvm-profdata-16 +LLVM_COV=llvm-cov-16 +CORPUS_DIR=corpus + +FUZZER_FLAGS=-g -O1 -fsanitize=fuzzer,address,undefined -I ../../bindings/c/include -I . + +COVERAGE_DIR=coverage_dir +COVERAGE_FLAGS=-g -fprofile-instr-generate -fcoverage-mapping -I ../../bindings/c/include -I . + +EXTERNAL_HEADERS=./fuzzer_func.h ../../bindings/c/include/molecule_reader.h + +all: fuzzer coverage + +show: $(COVERAGE_DIR)/fuzzer.profdata + $(LLVM_COV) show --instr-profile=$(COVERAGE_DIR)/fuzzer.profdata coverage + +report: $(COVERAGE_DIR)/fuzzer.profdata coverage $(EXTERNAL_HEADERS) + $(LLVM_COV) report --show-functions --instr-profile=$(COVERAGE_DIR)/fuzzer.profdata coverage $(EXTERNAL_HEADERS) + +fuzzer: $(EXTERNAL_HEADERS) + $(CC) $(FUZZER_FLAGS) fuzzer.c -o fuzzer + +coverage: $(EXTERNAL_HEADERS) + $(CC) $(COVERAGE_FLAGS) coverage.c fuzzer.c -o coverage + +start-fuzzer: fuzzer + ./fuzzer -max_len=255 -workers=$(NPROC) -jobs=$(NPROC) corpus + +clean: + rm -rf fuzzer coverage + +gen: + moleculec --language c --schema-file definitions.mol | clang-format > definitions.h + +manually-gen: + $(CC) -I ../bindings/c/include -I . manually-gen.c -o manually-gen + ./manually-gen + +fmt: + clang-format -style="{BasedOnStyle: google, IndentWidth: 4, SortIncludes: false}" -i *.c *.h + +%.profraw: coverage + LLVM_PROFILE_FILE=$@ ./coverage $(CORPUS_DIR)/* + +%.profdata: %.profraw + $(LLVM_PROFDATA) merge --sparse $< -o $@ + +.PHONY: all fuzzer coverage report + +.PRECIOUS: $(COVERAGE_DIR)/fuzzer.profraw $(COVERAGE_DIR)/fuzzer.profdata diff --git a/fuzzing/c/README.md b/fuzzing/c/README.md new file mode 100644 index 0000000..6344541 --- /dev/null +++ b/fuzzing/c/README.md @@ -0,0 +1,19 @@ + + +### Requirement + +* Linux +* LLVM version 16 + + +### Build + +``` +make all +``` + +### Run + +``` +make start-fuzzer +``` diff --git a/fuzzing/c/corpus/.gitignore b/fuzzing/c/corpus/.gitignore new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/fuzzing/c/corpus/.gitignore @@ -0,0 +1 @@ +* diff --git a/fuzzing/c/coverage.c b/fuzzing/c/coverage.c new file mode 100644 index 0000000..02e7ca3 --- /dev/null +++ b/fuzzing/c/coverage.c @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// This main() function can be linked to a fuzz target (i.e. a library +// that exports LLVMFuzzerTestOneInput() and possibly LLVMFuzzerInitialize()) +// instead of libFuzzer. This main() function will not perform any fuzzing +// but will simply feed all input files one by one to the fuzz target. +// +// Use this file to provide reproducers for bugs when linking against libFuzzer +// or other fuzzing engine is undesirable. +//===----------------------------------------------------------------------===*/ +#include +#include +#include + +extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size); +__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv); + +int main(int argc, char **argv) { + fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1); + if (LLVMFuzzerInitialize) LLVMFuzzerInitialize(&argc, &argv); + for (int i = 1; i < argc; i++) { + fprintf(stderr, "Running: %s\n", argv[i]); + FILE *f = fopen(argv[i], "r"); + assert(f); + fseek(f, 0, SEEK_END); + size_t len = ftell(f); + fseek(f, 0, SEEK_SET); + unsigned char *buf = (unsigned char *)malloc(len); + size_t n_read = fread(buf, 1, len, f); + fclose(f); + assert(n_read == len); + LLVMFuzzerTestOneInput(buf, len); + free(buf); + fprintf(stderr, "Done: %s: (%zd bytes)\n", argv[i], n_read); + } +} diff --git a/fuzzing/c/definitions.h b/fuzzing/c/definitions.h new file mode 100644 index 0000000..889c6ef --- /dev/null +++ b/fuzzing/c/definitions.h @@ -0,0 +1,424 @@ +// Generated by Molecule 0.7.5 + +#define MOLECULEC_VERSION 7005 +#define MOLECULE_API_VERSION_MIN 7000 + +#include "molecule_reader.h" +#include "molecule_builder.h" + +#ifndef DEFINITIONS_H +#define DEFINITIONS_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef MOLECULE_API_DECORATOR +#define __DEFINE_MOLECULE_API_DECORATOR_DEFINITIONS +#define MOLECULE_API_DECORATOR +#endif /* MOLECULE_API_DECORATOR */ + +/* + * Reader APIs + */ + +#define MolReader_ArrayType_verify(s, c) mol_verify_fixed_size(s, 3) +#define MolReader_ArrayType_get_nth0(s) mol_slice_by_offset(s, 0, 1) +#define MolReader_ArrayType_get_nth1(s) mol_slice_by_offset(s, 1, 1) +#define MolReader_ArrayType_get_nth2(s) mol_slice_by_offset(s, 2, 1) +#define MolReader_StructType_verify(s, c) mol_verify_fixed_size(s, 4) +#define MolReader_StructType_get_f1(s) mol_slice_by_offset(s, 0, 3) +#define MolReader_StructType_get_f2(s) mol_slice_by_offset(s, 3, 1) +#define MolReader_FixVecType_verify(s, c) mol_fixvec_verify(s, 1) +#define MolReader_FixVecType_length(s) mol_fixvec_length(s) +#define MolReader_FixVecType_get(s, i) mol_fixvec_slice_by_index(s, 1, i) +#define MolReader_FixVecType_raw_bytes(s) mol_fixvec_slice_raw_bytes(s) +MOLECULE_API_DECORATOR mol_errno MolReader_DynVecType_verify(const mol_seg_t *, + bool); +#define MolReader_DynVecType_length(s) mol_dynvec_length(s) +#define MolReader_DynVecType_get(s, i) mol_dynvec_slice_by_index(s, i) +MOLECULE_API_DECORATOR mol_errno MolReader_OptType_verify(const mol_seg_t *, + bool); +#define MolReader_OptType_is_none(s) mol_option_is_none(s) +MOLECULE_API_DECORATOR mol_errno MolReader_TableType_verify(const mol_seg_t *, + bool); +#define MolReader_TableType_actual_field_count(s) \ + mol_table_actual_field_count(s) +#define MolReader_TableType_has_extra_fields(s) mol_table_has_extra_fields(s, 5) +#define MolReader_TableType_get_f1(s) mol_table_slice_by_index(s, 0) +#define MolReader_TableType_get_f2(s) mol_table_slice_by_index(s, 1) +#define MolReader_TableType_get_f3(s) mol_table_slice_by_index(s, 2) +#define MolReader_TableType_get_f4(s) mol_table_slice_by_index(s, 3) +#define MolReader_TableType_get_f5(s) mol_table_slice_by_index(s, 4) +MOLECULE_API_DECORATOR mol_errno MolReader_UnionType_verify(const mol_seg_t *, + bool); +#define MolReader_UnionType_unpack(s) mol_union_unpack(s) + +/* + * Builder APIs + */ + +#define MolBuilder_ArrayType_init(b) mol_builder_initialize_fixed_size(b, 3) +#define MolBuilder_ArrayType_set_nth0(b, p) \ + mol_builder_set_byte_by_offset(b, 0, p) +#define MolBuilder_ArrayType_set_nth1(b, p) \ + mol_builder_set_byte_by_offset(b, 1, p) +#define MolBuilder_ArrayType_set_nth2(b, p) \ + mol_builder_set_byte_by_offset(b, 2, p) +#define MolBuilder_ArrayType_build(b) mol_builder_finalize_simple(b) +#define MolBuilder_ArrayType_clear(b) mol_builder_discard(b) +#define MolBuilder_StructType_init(b) mol_builder_initialize_fixed_size(b, 4) +#define MolBuilder_StructType_set_f1(b, p) mol_builder_set_by_offset(b, 0, p, 3) +#define MolBuilder_StructType_set_f2(b, p) \ + mol_builder_set_byte_by_offset(b, 3, p) +#define MolBuilder_StructType_build(b) mol_builder_finalize_simple(b) +#define MolBuilder_StructType_clear(b) mol_builder_discard(b) +#define MolBuilder_FixVecType_init(b) mol_fixvec_builder_initialize(b, 16) +#define MolBuilder_FixVecType_push(b, p) mol_fixvec_builder_push_byte(b, p) +#define MolBuilder_FixVecType_build(b) mol_fixvec_builder_finalize(b) +#define MolBuilder_FixVecType_clear(b) mol_builder_discard(b) +#define MolBuilder_DynVecType_init(b) \ + mol_builder_initialize_with_capacity(b, 64, 64) +#define MolBuilder_DynVecType_push(b, p, l) mol_dynvec_builder_push(b, p, l) +#define MolBuilder_DynVecType_build(b) mol_dynvec_builder_finalize(b) +#define MolBuilder_DynVecType_clear(b) mol_builder_discard(b) +#define MolBuilder_OptType_init(b) mol_builder_initialize_fixed_size(b, 0) +#define MolBuilder_OptType_set(b, p, l) mol_option_builder_set(b, p, l) +#define MolBuilder_OptType_build(b) mol_builder_finalize_simple(b) +#define MolBuilder_OptType_clear(b) mol_builder_discard(b) +#define MolBuilder_TableType_init(b) mol_table_builder_initialize(b, 256, 5) +#define MolBuilder_TableType_set_f1(b, p, l) mol_table_builder_add(b, 0, p, l) +#define MolBuilder_TableType_set_f2(b, p, l) mol_table_builder_add(b, 1, p, l) +#define MolBuilder_TableType_set_f3(b, p, l) mol_table_builder_add(b, 2, p, l) +#define MolBuilder_TableType_set_f4(b, p, l) mol_table_builder_add(b, 3, p, l) +#define MolBuilder_TableType_set_f5(b, p, l) mol_table_builder_add(b, 4, p, l) +MOLECULE_API_DECORATOR mol_seg_res_t MolBuilder_TableType_build(mol_builder_t); +#define MolBuilder_TableType_clear(b) mol_builder_discard(b) +#define MolBuilder_UnionType_init(b) \ + mol_union_builder_initialize(b, 8, 0, MolDefault_ArrayType, 3) +#define MolBuilder_UnionType_set_ArrayType(b, p, l) \ + mol_union_builder_set(b, 0, p, l) +#define MolBuilder_UnionType_set_StructType(b, p, l) \ + mol_union_builder_set(b, 1, p, l) +#define MolBuilder_UnionType_set_FixVecType(b, p, l) \ + mol_union_builder_set(b, 2, p, l) +#define MolBuilder_UnionType_set_DynVecType(b, p, l) \ + mol_union_builder_set(b, 3, p, l) +#define MolBuilder_UnionType_set_TableType(b, p, l) \ + mol_union_builder_set(b, 4, p, l) +#define MolBuilder_UnionType_build(b) mol_builder_finalize_simple(b) +#define MolBuilder_UnionType_clear(b) mol_builder_discard(b) + +/* + * Default Value + */ + +#define ____ 0x00 + +MOLECULE_API_DECORATOR const uint8_t MolDefault_ArrayType[3] = {____, ____, + ____}; +MOLECULE_API_DECORATOR const uint8_t MolDefault_StructType[4] = {____, ____, + ____, ____}; +MOLECULE_API_DECORATOR const uint8_t MolDefault_FixVecType[4] = {____, ____, + ____, ____}; +MOLECULE_API_DECORATOR const uint8_t MolDefault_DynVecType[4] = {0x04, ____, + ____, ____}; +MOLECULE_API_DECORATOR const uint8_t MolDefault_OptType[0] = {}; +MOLECULE_API_DECORATOR const uint8_t MolDefault_TableType[39] = { + 0x27, ____, ____, ____, 0x18, ____, ____, ____, 0x1c, ____, + ____, ____, 0x20, ____, ____, ____, 0x24, ____, ____, ____, + 0x27, ____, ____, ____, ____, ____, ____, ____, 0x04, ____, + ____, ____, ____, ____, ____, ____, ____, ____, ____, +}; +MOLECULE_API_DECORATOR const uint8_t MolDefault_UnionType[7] = { + ____, ____, ____, ____, ____, ____, ____, +}; + +#undef ____ + +/* + * Reader Functions + */ + +MOLECULE_API_DECORATOR mol_errno +MolReader_DynVecType_verify(const mol_seg_t *input, bool compatible) { + if (input->size < MOL_NUM_T_SIZE) { + return MOL_ERR_HEADER; + } + uint8_t *ptr = input->ptr; + mol_num_t total_size = mol_unpack_number(ptr); + if (input->size != total_size) { + return MOL_ERR_TOTAL_SIZE; + } + if (input->size == MOL_NUM_T_SIZE) { + return MOL_OK; + } + if (input->size < MOL_NUM_T_SIZE * 2) { + return MOL_ERR_HEADER; + } + ptr += MOL_NUM_T_SIZE; + mol_num_t offset = mol_unpack_number(ptr); + if (offset % 4 > 0 || offset < MOL_NUM_T_SIZE * 2) { + return MOL_ERR_OFFSET; + } + mol_num_t item_count = offset / 4 - 1; + if (input->size < MOL_NUM_T_SIZE * (item_count + 1)) { + return MOL_ERR_HEADER; + } + mol_num_t end; + for (mol_num_t i = 1; i < item_count; i++) { + ptr += MOL_NUM_T_SIZE; + end = mol_unpack_number(ptr); + if (offset > end) { + return MOL_ERR_OFFSET; + } + mol_seg_t inner; + inner.ptr = input->ptr + offset; + inner.size = end - offset; + if (mol_contained_by(&inner, input) != MOL_OK) { + return MOL_ERR_OFFSET; + } + mol_errno errno = MolReader_FixVecType_verify(&inner, compatible); + if (errno != MOL_OK) { + return MOL_ERR_DATA; + } + offset = end; + } + if (offset > total_size) { + return MOL_ERR_OFFSET; + } + mol_seg_t inner; + inner.ptr = input->ptr + offset; + inner.size = total_size - offset; + if (mol_contained_by(&inner, input) != MOL_OK) { + return MOL_ERR_OFFSET; + } + return MolReader_FixVecType_verify(&inner, compatible); +} +MOLECULE_API_DECORATOR mol_errno +MolReader_OptType_verify(const mol_seg_t *input, bool compatible) { + if (input->size != 0) { + return MolReader_DynVecType_verify(input, compatible); + } else { + return MOL_OK; + } +} +MOLECULE_API_DECORATOR mol_errno +MolReader_TableType_verify(const mol_seg_t *input, bool compatible) { + if (input->size < MOL_NUM_T_SIZE) { + return MOL_ERR_HEADER; + } + uint8_t *ptr = input->ptr; + mol_num_t total_size = mol_unpack_number(ptr); + if (input->size != total_size) { + return MOL_ERR_TOTAL_SIZE; + } + if (input->size < MOL_NUM_T_SIZE * 2) { + return MOL_ERR_HEADER; + } + ptr += MOL_NUM_T_SIZE; + mol_num_t offset = mol_unpack_number(ptr); + if (offset % 4 > 0 || offset < MOL_NUM_T_SIZE * 2) { + return MOL_ERR_OFFSET; + } + mol_num_t field_count = offset / 4 - 1; + if (field_count < 5) { + return MOL_ERR_FIELD_COUNT; + } else if (!compatible && field_count > 5) { + return MOL_ERR_FIELD_COUNT; + } + if (input->size < MOL_NUM_T_SIZE * (field_count + 1)) { + return MOL_ERR_HEADER; + } + mol_num_t offsets[field_count + 1]; + offsets[0] = offset; + for (mol_num_t i = 1; i < field_count; i++) { + ptr += MOL_NUM_T_SIZE; + offsets[i] = mol_unpack_number(ptr); + if (offsets[i - 1] > offsets[i]) { + return MOL_ERR_OFFSET; + } + } + if (offsets[field_count - 1] > total_size) { + return MOL_ERR_OFFSET; + } + offsets[field_count] = total_size; + mol_seg_t inner; + mol_errno errno; + inner.ptr = input->ptr + offsets[0]; + inner.size = offsets[1] - offsets[0]; + if (mol_contained_by(&inner, input) != MOL_OK) { + return MOL_ERR_OFFSET; + } + errno = MolReader_FixVecType_verify(&inner, compatible); + if (errno != MOL_OK) { + return MOL_ERR_DATA; + } + inner.ptr = input->ptr + offsets[1]; + inner.size = offsets[2] - offsets[1]; + if (mol_contained_by(&inner, input) != MOL_OK) { + return MOL_ERR_OFFSET; + } + errno = MolReader_DynVecType_verify(&inner, compatible); + if (errno != MOL_OK) { + return MOL_ERR_DATA; + } + inner.ptr = input->ptr + offsets[2]; + inner.size = offsets[3] - offsets[2]; + if (mol_contained_by(&inner, input) != MOL_OK) { + return MOL_ERR_OFFSET; + } + errno = MolReader_StructType_verify(&inner, compatible); + if (errno != MOL_OK) { + return MOL_ERR_DATA; + } + inner.ptr = input->ptr + offsets[3]; + inner.size = offsets[4] - offsets[3]; + if (mol_contained_by(&inner, input) != MOL_OK) { + return MOL_ERR_OFFSET; + } + errno = MolReader_ArrayType_verify(&inner, compatible); + if (errno != MOL_OK) { + return MOL_ERR_DATA; + } + inner.ptr = input->ptr + offsets[4]; + inner.size = offsets[5] - offsets[4]; + if (mol_contained_by(&inner, input) != MOL_OK) { + return MOL_ERR_OFFSET; + } + errno = MolReader_OptType_verify(&inner, compatible); + if (errno != MOL_OK) { + return MOL_ERR_DATA; + } + return MOL_OK; +} +MOLECULE_API_DECORATOR mol_errno +MolReader_UnionType_verify(const mol_seg_t *input, bool compatible) { + if (input->size < MOL_NUM_T_SIZE) { + return MOL_ERR_HEADER; + } + mol_num_t item_id = mol_unpack_number(input->ptr); + mol_seg_t inner; + inner.ptr = input->ptr + MOL_NUM_T_SIZE; + inner.size = input->size - MOL_NUM_T_SIZE; + switch (item_id) { + case 0: + return MolReader_ArrayType_verify(&inner, compatible); + case 1: + return MolReader_StructType_verify(&inner, compatible); + case 2: + return MolReader_FixVecType_verify(&inner, compatible); + case 3: + return MolReader_DynVecType_verify(&inner, compatible); + case 4: + return MolReader_TableType_verify(&inner, compatible); + default: + return MOL_ERR_UNKNOWN_ITEM; + } +} + +/* + * Builder Functions + */ + +MOLECULE_API_DECORATOR mol_seg_res_t +MolBuilder_TableType_build(mol_builder_t builder) { + mol_seg_res_t res; + res.errno = MOL_OK; + mol_num_t offset = 24; + mol_num_t len; + res.seg.size = offset; + len = builder.number_ptr[1]; + res.seg.size += len == 0 ? 4 : len; + len = builder.number_ptr[3]; + res.seg.size += len == 0 ? 4 : len; + len = builder.number_ptr[5]; + res.seg.size += len == 0 ? 4 : len; + len = builder.number_ptr[7]; + res.seg.size += len == 0 ? 3 : len; + len = builder.number_ptr[9]; + res.seg.size += len == 0 ? 0 : len; + res.seg.ptr = (uint8_t *)malloc(res.seg.size); + uint8_t *dst = res.seg.ptr; + mol_pack_number(dst, &res.seg.size); + dst += MOL_NUM_T_SIZE; + mol_pack_number(dst, &offset); + dst += MOL_NUM_T_SIZE; + len = builder.number_ptr[1]; + offset += len == 0 ? 4 : len; + mol_pack_number(dst, &offset); + dst += MOL_NUM_T_SIZE; + len = builder.number_ptr[3]; + offset += len == 0 ? 4 : len; + mol_pack_number(dst, &offset); + dst += MOL_NUM_T_SIZE; + len = builder.number_ptr[5]; + offset += len == 0 ? 4 : len; + mol_pack_number(dst, &offset); + dst += MOL_NUM_T_SIZE; + len = builder.number_ptr[7]; + offset += len == 0 ? 3 : len; + mol_pack_number(dst, &offset); + dst += MOL_NUM_T_SIZE; + len = builder.number_ptr[9]; + offset += len == 0 ? 0 : len; + uint8_t *src = builder.data_ptr; + len = builder.number_ptr[1]; + if (len == 0) { + len = 4; + memcpy(dst, &MolDefault_FixVecType, len); + } else { + mol_num_t of = builder.number_ptr[0]; + memcpy(dst, src + of, len); + } + dst += len; + len = builder.number_ptr[3]; + if (len == 0) { + len = 4; + memcpy(dst, &MolDefault_DynVecType, len); + } else { + mol_num_t of = builder.number_ptr[2]; + memcpy(dst, src + of, len); + } + dst += len; + len = builder.number_ptr[5]; + if (len == 0) { + len = 4; + memcpy(dst, &MolDefault_StructType, len); + } else { + mol_num_t of = builder.number_ptr[4]; + memcpy(dst, src + of, len); + } + dst += len; + len = builder.number_ptr[7]; + if (len == 0) { + len = 3; + memcpy(dst, &MolDefault_ArrayType, len); + } else { + mol_num_t of = builder.number_ptr[6]; + memcpy(dst, src + of, len); + } + dst += len; + len = builder.number_ptr[9]; + if (len == 0) { + len = 0; + memcpy(dst, &MolDefault_OptType, len); + } else { + mol_num_t of = builder.number_ptr[8]; + memcpy(dst, src + of, len); + } + dst += len; + mol_builder_discard(builder); + return res; +} + +#ifdef __DEFINE_MOLECULE_API_DECORATOR_DEFINITIONS +#undef MOLECULE_API_DECORATOR +#undef __DEFINE_MOLECULE_API_DECORATOR_DEFINITIONS +#endif /* __DEFINE_MOLECULE_API_DECORATOR_DEFINITIONS */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DEFINITIONS_H */ diff --git a/fuzzing/c/definitions.mol b/fuzzing/c/definitions.mol new file mode 100644 index 0000000..77c2493 --- /dev/null +++ b/fuzzing/c/definitions.mol @@ -0,0 +1,26 @@ +array ArrayType [byte; 3]; + +struct StructType { + f1: ArrayType, + f2: byte, +} + +vector FixVecType ; +vector DynVecType ; +option OptType (DynVecType); + +table TableType { + f1: FixVecType, + f2: DynVecType, + f3: StructType, + f4: ArrayType, + f5: OptType, +} + +union UnionType { + ArrayType, + StructType, + FixVecType, + DynVecType, + TableType, +} diff --git a/fuzzing/c/fuzzer.c b/fuzzing/c/fuzzer.c new file mode 100644 index 0000000..f41caf9 --- /dev/null +++ b/fuzzing/c/fuzzer.c @@ -0,0 +1,6 @@ + +#include "fuzzer_func.h" + +int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { + return start_fuzzing(data, size); +} diff --git a/fuzzing/c/fuzzer_func.h b/fuzzing/c/fuzzer_func.h new file mode 100644 index 0000000..fbbe9eb --- /dev/null +++ b/fuzzing/c/fuzzer_func.h @@ -0,0 +1,100 @@ + +#ifndef _FUZZER_FUZZER_FUNC_H_ +#define _FUZZER_FUZZER_FUNC_H_ +#include +#include +#include + +#include "definitions.h" + +void access_seg(mol_seg_t seg, int* result) { + if (seg.size > 0) { + *result += (int)seg.ptr[0]; + *result += (int)seg.ptr[seg.size - 1]; + } +} + +void access_array(mol_seg_t seg, int* result) { + if (MolReader_ArrayType_verify(&seg, false) == 0) { + mol_seg_t first = MolReader_ArrayType_get_nth0(&seg); + mol_seg_t last = MolReader_ArrayType_get_nth2(&seg); + access_seg(first, result); + access_seg(last, result); + } +} + +void access_struct(mol_seg_t seg, int* result) { + if (MolReader_StructType_verify(&seg, false) == 0) { + mol_seg_t f1 = MolReader_StructType_get_f1(&seg); + mol_seg_t f2 = MolReader_StructType_get_f2(&seg); + access_seg(f1, result); + access_seg(f2, result); + } +} + +void access_fixvec(mol_seg_t seg, int* result) { + if (MolReader_FixVecType_verify(&seg, false) == 0) { + mol_seg_t data = MolReader_FixVecType_raw_bytes(&seg); + access_seg(data, result); + } +} + +void access_dynvec(mol_seg_t seg, int* result) { + if (MolReader_DynVecType_verify(&seg, false) == 0) { + uint32_t length = MolReader_DynVecType_length(&seg); + for (uint32_t i = 0; i < length; i++) { + mol_seg_res_t element = MolReader_DynVecType_get(&seg, i); + access_seg(element.seg, result); + } + mol_seg_res_t out_of_bound = MolReader_DynVecType_get(&seg, length); + assert(out_of_bound.errno != 0); + } +} + +void access_opt(mol_seg_t seg, int* result) { + if (MolReader_OptType_verify(&seg, false) == 0) { + if (MolReader_OptType_is_none(&seg)) { + return; + } else { + access_dynvec(seg, result); + } + } +} + +void access_table(mol_seg_t seg, int* result) { + if (MolReader_TableType_verify(&seg, false) == 0) { + mol_seg_t fixvec = MolReader_TableType_get_f1(&seg); + access_fixvec(fixvec, result); + mol_seg_t dynvec = MolReader_TableType_get_f2(&seg); + access_dynvec(dynvec, result); + mol_seg_t struct_ = MolReader_TableType_get_f3(&seg); + access_struct(struct_, result); + mol_seg_t array = MolReader_TableType_get_f4(&seg); + access_array(array, result); + mol_seg_t opt = MolReader_TableType_get_f5(&seg); + access_opt(opt, result); + } +} + +void access_union(mol_seg_t seg, int* result) { + if (MolReader_UnionType_verify(&seg, false) == 0) { + mol_union_t data = MolReader_UnionType_unpack(&seg); + access_seg(data.seg, result); + } +} + +int start_fuzzing(uint8_t* data, size_t size) { + int result = 0; + mol_seg_t seg = {.ptr = data, .size = size}; + + access_array(seg, &result); + access_struct(seg, &result); + access_fixvec(seg, &result); + access_dynvec(seg, &result); + access_table(seg, &result); + access_union(seg, &result); + + return result; +} + +#endif diff --git a/fuzzing/c/manually-gen.c b/fuzzing/c/manually-gen.c new file mode 100644 index 0000000..de4bf1f --- /dev/null +++ b/fuzzing/c/manually-gen.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include "definitions.h" + +int write(uint8_t* data, size_t length, const char* file_name) { + FILE* file = fopen(file_name, "wb"); + if (file == NULL) { + fprintf(stderr, "Error: Unable to open file %s\n", file_name); + return -1; + } + + size_t bytes_written = + fwrite(data, sizeof(uint8_t), length, file); // Write data to file + if (bytes_written != length) { + fprintf(stderr, "Error: Unable to write all data to file\n"); + fclose(file); + return -1; + } + printf("%s is generated", file_name); + fclose(file); + return 0; +} + +int main() { + mol_builder_t fixvec_builder = {0}; + MolBuilder_FixVecType_init(&fixvec_builder); + MolBuilder_FixVecType_push(&fixvec_builder, 1); + mol_seg_res_t res = MolBuilder_FixVecType_build(fixvec_builder); + assert(res.errno == 0); + mol_seg_t fix_vec = res.seg; + + mol_builder_t dynvec_builder = {0}; + MolBuilder_DynVecType_init(&dynvec_builder); + MolBuilder_DynVecType_push(&dynvec_builder, fix_vec.ptr, fix_vec.size); + res = MolBuilder_DynVecType_build(dynvec_builder); + assert(res.errno == 0); + mol_seg_t dyn_vec = res.seg; + + uint8_t array[3] = {0}; + uint8_t byte = 0; + mol_builder_t struct_builder = {0}; + MolBuilder_StructType_init(&struct_builder); + MolBuilder_StructType_set_f1(&struct_builder, array); + MolBuilder_StructType_set_f2(&struct_builder, byte); + res = MolBuilder_StructType_build(struct_builder); + assert(res.errno == 0); + mol_seg_t struct_ = res.seg; + + mol_builder_t table_builder = {0}; + MolBuilder_TableType_init(&table_builder); + MolBuilder_TableType_set_f1(&table_builder, fix_vec.ptr, fix_vec.size); + MolBuilder_TableType_set_f2(&table_builder, dyn_vec.ptr, dyn_vec.size); + MolBuilder_TableType_set_f3(&table_builder, struct_.ptr, struct_.size); + MolBuilder_TableType_set_f4(&table_builder, array, 3); + res = MolBuilder_TableType_build(table_builder); + assert(res.errno == 0); + mol_seg_t table = res.seg; + + return write(table.ptr, table.size, "corpus/sample_table"); +} diff --git a/fuzzing/rust/.gitignore b/fuzzing/rust/.gitignore new file mode 100644 index 0000000..58a66c9 --- /dev/null +++ b/fuzzing/rust/.gitignore @@ -0,0 +1,2 @@ +reader.html +data.html diff --git a/fuzzing/rust/Cargo.lock b/fuzzing/rust/Cargo.lock new file mode 100644 index 0000000..23ee5f0 --- /dev/null +++ b/fuzzing/rust/Cargo.lock @@ -0,0 +1,37 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "faster-hex" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e2ce894d53b295cf97b05685aa077950ff3e8541af83217fc720a6437169f8" + +[[package]] +name = "molecule" +version = "0.8.0" +dependencies = [ + "bytes", + "cfg-if", + "faster-hex", +] + +[[package]] +name = "molecule-fuzzing" +version = "0.1.0" +dependencies = [ + "molecule", +] diff --git a/fuzzing/rust/Cargo.toml b/fuzzing/rust/Cargo.toml new file mode 100644 index 0000000..61f3ce0 --- /dev/null +++ b/fuzzing/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "molecule-fuzzing" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +molecule = { path = "../../bindings/rust" } diff --git a/fuzzing/rust/README.md b/fuzzing/rust/README.md new file mode 100644 index 0000000..60ad940 --- /dev/null +++ b/fuzzing/rust/README.md @@ -0,0 +1,19 @@ + +### Introduction + +See https://rust-fuzz.github.io/book/introduction.html + +### Run +``` +cargo fuzz run data +``` + +### Coverage Report + +``` +cargo fuzz coverage data +cargo cov -- show target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release/data \ + --format=html \ + -instr-profile=fuzz/coverage/data/coverage.profdata \ + > data.html +``` diff --git a/fuzzing/rust/fuzz/.gitignore b/fuzzing/rust/fuzz/.gitignore new file mode 100644 index 0000000..1a45eee --- /dev/null +++ b/fuzzing/rust/fuzz/.gitignore @@ -0,0 +1,4 @@ +target +corpus +artifacts +coverage diff --git a/fuzzing/rust/fuzz/Cargo.lock b/fuzzing/rust/fuzz/Cargo.lock new file mode 100644 index 0000000..815caa1 --- /dev/null +++ b/fuzzing/rust/fuzz/Cargo.lock @@ -0,0 +1,94 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cc" +version = "1.0.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "faster-hex" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e2ce894d53b295cf97b05685aa077950ff3e8541af83217fc720a6437169f8" + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "molecule" +version = "0.8.0" +dependencies = [ + "bytes", + "cfg-if", + "faster-hex", +] + +[[package]] +name = "molecule-fuzzer" +version = "0.1.0" +dependencies = [ + "libfuzzer-sys", + "molecule-fuzzing", +] + +[[package]] +name = "molecule-fuzzing" +version = "0.1.0" +dependencies = [ + "molecule", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" diff --git a/fuzzing/rust/fuzz/Cargo.toml b/fuzzing/rust/fuzz/Cargo.toml new file mode 100644 index 0000000..208feec --- /dev/null +++ b/fuzzing/rust/fuzz/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "molecule-fuzzer" +version = "0.1.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" + +[dependencies.molecule-fuzzing] +path = ".." + +[[bin]] +name = "data" +path = "fuzz_targets/data.rs" +test = false +doc = false +bench = false diff --git a/fuzzing/rust/fuzz/fuzz_targets/data.rs b/fuzzing/rust/fuzz/fuzz_targets/data.rs new file mode 100644 index 0000000..e108066 --- /dev/null +++ b/fuzzing/rust/fuzz/fuzz_targets/data.rs @@ -0,0 +1,264 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use molecule_fuzzing::definitions::*; +use molecule_fuzzing::molecule::prelude::*; + +fn access_fixvec_reader(data: &[u8]) -> u64 { + if let Ok(_) = FixVecTypeReader::verify(data, false) { + let fixvec = FixVecTypeReader::new_unchecked(data); + let len = fixvec.len(); + if len > 0 { + let first: u8 = fixvec.get(0).unwrap().into(); + let last: u8 = fixvec.get(len-1).unwrap().into(); + first as u64 + last as u64 + } else { + 0 + } + } else { + 0 + } +} + +fn access_array_reader(data: &[u8]) -> u64 { + if let Ok(_) = ArrayTypeReader::verify(data, false) { + let array = ArrayTypeReader::new_unchecked(data); + let first : u8 = array.nth0().into(); + let last : u8 = array.nth2().into(); + first as u64 + last as u64 + } else { + 0 + } +} + +fn access_struct_reader(data: &[u8]) -> u64 { + if let Ok(_) = StructTypeReader::verify(data, false) { + let struct_ = StructTypeReader::new_unchecked(data); + let mut total: u64 = 0; + let f1 = struct_.f1(); + total += access_array(f1.as_slice()); + let f2 = struct_.f2(); + let f2_value: u8 = f2.into(); + total += f2_value as u64; + total + } else { + 0 + } +} + +fn access_dynvec_reader(data: &[u8]) -> u64 { + if let Ok(_) = DynVecTypeReader::verify(data, false) { + let dynvec = DynVecTypeReader::new_unchecked(data); + let mut total: u64 = 0; + let len = dynvec.len(); + if len > 0 { + let first = dynvec.get(0).unwrap(); + let last = dynvec.get(len - 1).unwrap(); + total += access_fixvec(first.raw_data()); + total += access_fixvec(last.raw_data()); + total + } else { + 0 + } + } else { + 0 + } +} + +fn access_opt_reader(data: &[u8]) -> u64 { + if let Ok(_) = OptTypeReader::verify(data, false) { + let opt = OptTypeReader::new_unchecked(data); + if opt.is_some() { + let dynvec = opt.to_opt().unwrap(); + access_dynvec(dynvec.as_slice()) + } else { + 0 + } + } else { + 0 + } +} + +fn access_table_reader(data: &[u8]) -> u64 { + let mut total: u64 = 0; + if let Ok(_) = TableTypeReader::verify(data, false) { + let tbl = TableTypeReader::new_unchecked(data); + let fixvec = tbl.f1(); + total += access_fixvec(fixvec.as_slice()); + let dynvec = tbl.f2(); + total += access_dynvec(dynvec.as_slice()); + let struct_ = tbl.f3(); + access_struct(struct_.as_slice()); + let array = tbl.f4(); + total += access_array(array.as_slice()); + let opt = tbl.f5(); + total += access_opt(opt.as_slice()); + } + total +} + +fn access_union_reader(data: &[u8]) -> u64 { + let mut total: u64 = 0; + if let Ok(_) = UnionTypeReader::verify(data, false) { + let union_ = UnionTypeReader::new_unchecked(data); + match union_.to_enum() { + UnionTypeUnionReader::ArrayType(array) => { + total += access_array(array.as_slice()); + }, + UnionTypeUnionReader::StructType(struct_) => { + total += access_struct(struct_.as_slice()); + }, + UnionTypeUnionReader::FixVecType(fixvec) => { + total += access_fixvec(fixvec.as_slice()); + }, + UnionTypeUnionReader::DynVecType(dynvec) => { + total += access_dynvec(dynvec.as_slice()); + }, + UnionTypeUnionReader::TableType(tbl) => { + total += access_table(tbl.as_slice()); + }, + } + } + total +} + +fn access_fixvec(data: &[u8]) -> u64 { + if let Ok(_) = FixVecTypeReader::verify(data, false) { + let fixvec = FixVecType::from_slice(data).unwrap(); + let len = fixvec.len(); + if len > 0 { + let first: u8 = fixvec.get(0).unwrap().into(); + let last: u8 = fixvec.get(len-1).unwrap().into(); + first as u64 + last as u64 + } else { + 0 + } + } else { + 0 + } +} + +fn access_array(data: &[u8]) -> u64 { + if let Ok(_) = ArrayTypeReader::verify(data, false) { + let array = ArrayType::from_slice(data).unwrap(); + let first : u8 = array.nth0().into(); + let last : u8 = array.nth2().into(); + first as u64 + last as u64 + } else { + 0 + } +} + +fn access_struct(data: &[u8]) -> u64 { + if let Ok(_) = StructTypeReader::verify(data, false) { + let struct_ = StructTypeReader::from_slice(data).unwrap(); + let mut total: u64 = 0; + let f1 = struct_.f1(); + total += access_array(f1.as_slice()); + let f2 = struct_.f2(); + let f2_value: u8 = f2.into(); + total += f2_value as u64; + total + } else { + 0 + } +} + +fn access_dynvec(data: &[u8]) -> u64 { + if let Ok(_) = DynVecTypeReader::verify(data, false) { + let dynvec = DynVecType::from_slice(data).unwrap(); + let mut total: u64 = 0; + let len = dynvec.len(); + if len > 0 { + let first = dynvec.get(0).unwrap(); + let last = dynvec.get(len - 1).unwrap(); + total += access_fixvec(&first.raw_data()); + total += access_fixvec(&last.raw_data()); + total + } else { + 0 + } + } else { + 0 + } +} + +fn access_opt(data: &[u8]) -> u64 { + if let Ok(_) = OptTypeReader::verify(data, false) { + let opt = OptType::from_slice(data).unwrap(); + if opt.is_some() { + let dynvec = opt.to_opt().unwrap(); + access_dynvec(dynvec.as_slice()) + } else { + 0 + } + } else { + 0 + } +} + +fn access_table(data: &[u8]) -> u64 { + let mut total: u64 = 0; + if let Ok(_) = TableTypeReader::verify(data, false) { + let tbl = TableType::from_slice(data).unwrap(); + let fixvec = tbl.f1(); + total += access_fixvec(fixvec.as_slice()); + let dynvec = tbl.f2(); + total += access_dynvec(dynvec.as_slice()); + let struct_ = tbl.f3(); + access_struct(struct_.as_slice()); + let array = tbl.f4(); + total += access_array(array.as_slice()); + let opt = tbl.f5(); + total += access_opt(opt.as_slice()); + } + total +} + + +fn access_union(data: &[u8]) -> u64 { + let mut total: u64 = 0; + if let Ok(_) = UnionTypeReader::verify(data, false) { + let union_ = UnionType::from_slice(data).unwrap(); + match union_.to_enum() { + UnionTypeUnion::ArrayType(array) => { + total += access_array(array.as_slice()); + }, + UnionTypeUnion::StructType(struct_) => { + total += access_struct(struct_.as_slice()); + }, + UnionTypeUnion::FixVecType(fixvec) => { + total += access_fixvec(fixvec.as_slice()); + }, + UnionTypeUnion::DynVecType(dynvec) => { + total += access_dynvec(dynvec.as_slice()); + }, + UnionTypeUnion::TableType(tbl) => { + total += access_table(tbl.as_slice()); + }, + } + } + total +} + +fuzz_target!(|data: &[u8]| { + let mut total : u64 = 0; + total += access_table_reader(data); + total += access_array_reader(data); + total += access_dynvec_reader(data); + total += access_fixvec_reader(data); + total += access_opt_reader(data); + total += access_struct_reader(data); + total += access_union_reader(data); + + total += access_table(data); + total += access_array(data); + total += access_dynvec(data); + total += access_fixvec(data); + total += access_opt(data); + total += access_struct(data); + total += access_union(data); + + + let _ = total; +}); diff --git a/fuzzing/rust/rust-toolchain.toml b/fuzzing/rust/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/fuzzing/rust/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/fuzzing/rust/src/definitions.rs b/fuzzing/rust/src/definitions.rs new file mode 100644 index 0000000..76fd769 --- /dev/null +++ b/fuzzing/rust/src/definitions.rs @@ -0,0 +1,1921 @@ +// Generated by Molecule 0.7.5 + +use molecule::prelude::*; +#[derive(Clone)] +pub struct ArrayType(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ArrayType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for ArrayType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for ArrayType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl ::core::default::Default for ArrayType { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ArrayType::new_unchecked(v) + } +} +impl ArrayType { + const DEFAULT_VALUE: [u8; 3] = [0, 0, 0]; + pub const TOTAL_SIZE: usize = 3; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 3; + pub fn nth0(&self) -> Byte { + Byte::new_unchecked(self.0.slice(0..1)) + } + pub fn nth1(&self) -> Byte { + Byte::new_unchecked(self.0.slice(1..2)) + } + pub fn nth2(&self) -> Byte { + Byte::new_unchecked(self.0.slice(2..3)) + } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() + } + pub fn as_reader<'r>(&'r self) -> ArrayTypeReader<'r> { + ArrayTypeReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for ArrayType { + type Builder = ArrayTypeBuilder; + const NAME: &'static str = "ArrayType"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ArrayType(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ArrayTypeReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ArrayTypeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().set([self.nth0(), self.nth1(), self.nth2()]) + } +} +#[derive(Clone, Copy)] +pub struct ArrayTypeReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ArrayTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ArrayTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ArrayTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl<'r> ArrayTypeReader<'r> { + pub const TOTAL_SIZE: usize = 3; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 3; + pub fn nth0(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[0..1]) + } + pub fn nth1(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[1..2]) + } + pub fn nth2(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[2..3]) + } + pub fn raw_data(&self) -> &'r [u8] { + self.as_slice() + } +} +impl<'r> molecule::prelude::Reader<'r> for ArrayTypeReader<'r> { + type Entity = ArrayType; + const NAME: &'static str = "ArrayTypeReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ArrayTypeReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); + } + Ok(()) + } +} +#[derive(Clone)] +pub struct ArrayTypeBuilder(pub(crate) [Byte; 3]); +impl ::core::fmt::Debug for ArrayTypeBuilder { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:?})", Self::NAME, &self.0[..]) + } +} +impl ::core::default::Default for ArrayTypeBuilder { + fn default() -> Self { + ArrayTypeBuilder([Byte::default(), Byte::default(), Byte::default()]) + } +} +impl ArrayTypeBuilder { + pub const TOTAL_SIZE: usize = 3; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 3; + pub fn set(mut self, v: [Byte; 3]) -> Self { + self.0 = v; + self + } + pub fn nth0(mut self, v: Byte) -> Self { + self.0[0] = v; + self + } + pub fn nth1(mut self, v: Byte) -> Self { + self.0[1] = v; + self + } + pub fn nth2(mut self, v: Byte) -> Self { + self.0[2] = v; + self + } +} +impl molecule::prelude::Builder for ArrayTypeBuilder { + type Entity = ArrayType; + const NAME: &'static str = "ArrayTypeBuilder"; + fn expected_length(&self) -> usize { + Self::TOTAL_SIZE + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(self.0[0].as_slice())?; + writer.write_all(self.0[1].as_slice())?; + writer.write_all(self.0[2].as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + ArrayType::new_unchecked(inner.into()) + } +} +impl From<[Byte; 3usize]> for ArrayType { + fn from(value: [Byte; 3usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Byte]> for ArrayType { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Byte]) -> Result { + Ok(Self::new_builder() + .set(<&[Byte; 3usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Byte; 3usize] { + #[track_caller] + fn from(value: ArrayType) -> Self { + [value.nth0(), value.nth1(), value.nth2()] + } +} +impl From<[u8; 3usize]> for ArrayType { + fn from(value: [u8; 3usize]) -> Self { + ArrayTypeReader::new_unchecked(&value).to_entity() + } +} +impl ::core::convert::TryFrom<&[u8]> for ArrayType { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; 3usize]>::try_from(value)?.into()) + } +} +impl From for [u8; 3usize] { + #[track_caller] + fn from(value: ArrayType) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From> for &'a [u8; 3usize] { + #[track_caller] + fn from(value: ArrayTypeReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From<&'a ArrayTypeReader<'a>> for &'a [u8; 3usize] { + #[track_caller] + fn from(value: &'a ArrayTypeReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +#[derive(Clone)] +pub struct StructType(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for StructType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for StructType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for StructType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "f1", self.f1())?; + write!(f, ", {}: {}", "f2", self.f2())?; + write!(f, " }}") + } +} +impl ::core::default::Default for StructType { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + StructType::new_unchecked(v) + } +} +impl StructType { + const DEFAULT_VALUE: [u8; 4] = [0, 0, 0, 0]; + pub const TOTAL_SIZE: usize = 4; + pub const FIELD_SIZES: [usize; 2] = [3, 1]; + pub const FIELD_COUNT: usize = 2; + pub fn f1(&self) -> ArrayType { + ArrayType::new_unchecked(self.0.slice(0..3)) + } + pub fn f2(&self) -> Byte { + Byte::new_unchecked(self.0.slice(3..4)) + } + pub fn as_reader<'r>(&'r self) -> StructTypeReader<'r> { + StructTypeReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for StructType { + type Builder = StructTypeBuilder; + const NAME: &'static str = "StructType"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + StructType(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + StructTypeReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + StructTypeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().f1(self.f1()).f2(self.f2()) + } +} +#[derive(Clone, Copy)] +pub struct StructTypeReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for StructTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for StructTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for StructTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "f1", self.f1())?; + write!(f, ", {}: {}", "f2", self.f2())?; + write!(f, " }}") + } +} +impl<'r> StructTypeReader<'r> { + pub const TOTAL_SIZE: usize = 4; + pub const FIELD_SIZES: [usize; 2] = [3, 1]; + pub const FIELD_COUNT: usize = 2; + pub fn f1(&self) -> ArrayTypeReader<'r> { + ArrayTypeReader::new_unchecked(&self.as_slice()[0..3]) + } + pub fn f2(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[3..4]) + } +} +impl<'r> molecule::prelude::Reader<'r> for StructTypeReader<'r> { + type Entity = StructType; + const NAME: &'static str = "StructTypeReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + StructTypeReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); + } + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct StructTypeBuilder { + pub(crate) f1: ArrayType, + pub(crate) f2: Byte, +} +impl StructTypeBuilder { + pub const TOTAL_SIZE: usize = 4; + pub const FIELD_SIZES: [usize; 2] = [3, 1]; + pub const FIELD_COUNT: usize = 2; + pub fn f1(mut self, v: ArrayType) -> Self { + self.f1 = v; + self + } + pub fn f2(mut self, v: Byte) -> Self { + self.f2 = v; + self + } +} +impl molecule::prelude::Builder for StructTypeBuilder { + type Entity = StructType; + const NAME: &'static str = "StructTypeBuilder"; + fn expected_length(&self) -> usize { + Self::TOTAL_SIZE + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(self.f1.as_slice())?; + writer.write_all(self.f2.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + StructType::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct FixVecType(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for FixVecType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for FixVecType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for FixVecType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl ::core::default::Default for FixVecType { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + FixVecType::new_unchecked(v) + } +} +impl FixVecType { + const DEFAULT_VALUE: [u8; 4] = [0, 0, 0, 0]; + pub const ITEM_SIZE: usize = 1; + pub fn total_size(&self) -> usize { + molecule::NUMBER_SIZE + Self::ITEM_SIZE * self.item_count() + } + pub fn item_count(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> Byte { + let start = molecule::NUMBER_SIZE + Self::ITEM_SIZE * idx; + let end = start + Self::ITEM_SIZE; + Byte::new_unchecked(self.0.slice(start..end)) + } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.0.slice(molecule::NUMBER_SIZE..) + } + pub fn as_reader<'r>(&'r self) -> FixVecTypeReader<'r> { + FixVecTypeReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for FixVecType { + type Builder = FixVecTypeBuilder; + const NAME: &'static str = "FixVecType"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + FixVecType(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + FixVecTypeReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + FixVecTypeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().extend(self.into_iter()) + } +} +#[derive(Clone, Copy)] +pub struct FixVecTypeReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for FixVecTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for FixVecTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for FixVecTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl<'r> FixVecTypeReader<'r> { + pub const ITEM_SIZE: usize = 1; + pub fn total_size(&self) -> usize { + molecule::NUMBER_SIZE + Self::ITEM_SIZE * self.item_count() + } + pub fn item_count(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option> { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> ByteReader<'r> { + let start = molecule::NUMBER_SIZE + Self::ITEM_SIZE * idx; + let end = start + Self::ITEM_SIZE; + ByteReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn raw_data(&self) -> &'r [u8] { + &self.as_slice()[molecule::NUMBER_SIZE..] + } +} +impl<'r> molecule::prelude::Reader<'r> for FixVecTypeReader<'r> { + type Entity = FixVecType; + const NAME: &'static str = "FixVecTypeReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + FixVecTypeReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let item_count = molecule::unpack_number(slice) as usize; + if item_count == 0 { + if slice_len != molecule::NUMBER_SIZE { + return ve!(Self, TotalSizeNotMatch, molecule::NUMBER_SIZE, slice_len); + } + return Ok(()); + } + let total_size = molecule::NUMBER_SIZE + Self::ITEM_SIZE * item_count; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct FixVecTypeBuilder(pub(crate) Vec); +impl FixVecTypeBuilder { + pub const ITEM_SIZE: usize = 1; + pub fn set(mut self, v: Vec) -> Self { + self.0 = v; + self + } + pub fn push(mut self, v: Byte) -> Self { + self.0.push(v); + self + } + pub fn extend>(mut self, iter: T) -> Self { + for elem in iter { + self.0.push(elem); + } + self + } + pub fn replace(&mut self, index: usize, v: Byte) -> Option { + self.0 + .get_mut(index) + .map(|item| ::core::mem::replace(item, v)) + } +} +impl molecule::prelude::Builder for FixVecTypeBuilder { + type Entity = FixVecType; + const NAME: &'static str = "FixVecTypeBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE + Self::ITEM_SIZE * self.0.len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(&molecule::pack_number(self.0.len() as molecule::Number))?; + for inner in &self.0[..] { + writer.write_all(inner.as_slice())?; + } + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + FixVecType::new_unchecked(inner.into()) + } +} +pub struct FixVecTypeIterator(FixVecType, usize, usize); +impl ::core::iter::Iterator for FixVecTypeIterator { + type Item = Byte; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl ::core::iter::ExactSizeIterator for FixVecTypeIterator { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::IntoIterator for FixVecType { + type Item = Byte; + type IntoIter = FixVecTypeIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + FixVecTypeIterator(self, 0, len) + } +} +impl ::core::iter::FromIterator for FixVecType { + fn from_iter>(iter: T) -> Self { + Self::new_builder().extend(iter).build() + } +} +impl ::core::iter::FromIterator for FixVecType { + fn from_iter>(iter: T) -> Self { + Self::new_builder() + .extend(iter.into_iter().map(Into::into)) + .build() + } +} +#[derive(Clone)] +pub struct DynVecType(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for DynVecType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for DynVecType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for DynVecType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl ::core::default::Default for DynVecType { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + DynVecType::new_unchecked(v) + } +} +impl DynVecType { + const DEFAULT_VALUE: [u8; 4] = [4, 0, 0, 0]; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> FixVecType { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + FixVecType::new_unchecked(self.0.slice(start..)) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + FixVecType::new_unchecked(self.0.slice(start..end)) + } + } + pub fn as_reader<'r>(&'r self) -> DynVecTypeReader<'r> { + DynVecTypeReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for DynVecType { + type Builder = DynVecTypeBuilder; + const NAME: &'static str = "DynVecType"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + DynVecType(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + DynVecTypeReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + DynVecTypeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().extend(self.into_iter()) + } +} +#[derive(Clone, Copy)] +pub struct DynVecTypeReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for DynVecTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for DynVecTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for DynVecTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl<'r> DynVecTypeReader<'r> { + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option> { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> FixVecTypeReader<'r> { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + FixVecTypeReader::new_unchecked(&self.as_slice()[start..]) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + FixVecTypeReader::new_unchecked(&self.as_slice()[start..end]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for DynVecTypeReader<'r> { + type Entity = DynVecType; + const NAME: &'static str = "DynVecTypeReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + DynVecTypeReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len == molecule::NUMBER_SIZE { + return Ok(()); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!( + Self, + TotalSizeNotMatch, + molecule::NUMBER_SIZE * 2, + slice_len + ); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + for pair in offsets.windows(2) { + let start = pair[0]; + let end = pair[1]; + FixVecTypeReader::verify(&slice[start..end], compatible)?; + } + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct DynVecTypeBuilder(pub(crate) Vec); +impl DynVecTypeBuilder { + pub fn set(mut self, v: Vec) -> Self { + self.0 = v; + self + } + pub fn push(mut self, v: FixVecType) -> Self { + self.0.push(v); + self + } + pub fn extend>(mut self, iter: T) -> Self { + for elem in iter { + self.0.push(elem); + } + self + } + pub fn replace(&mut self, index: usize, v: FixVecType) -> Option { + self.0 + .get_mut(index) + .map(|item| ::core::mem::replace(item, v)) + } +} +impl molecule::prelude::Builder for DynVecTypeBuilder { + type Entity = DynVecType; + const NAME: &'static str = "DynVecTypeBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (self.0.len() + 1) + + self + .0 + .iter() + .map(|inner| inner.as_slice().len()) + .sum::() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let item_count = self.0.len(); + if item_count == 0 { + writer.write_all(&molecule::pack_number( + molecule::NUMBER_SIZE as molecule::Number, + ))?; + } else { + let (total_size, offsets) = self.0.iter().fold( + ( + molecule::NUMBER_SIZE * (item_count + 1), + Vec::with_capacity(item_count), + ), + |(start, mut offsets), inner| { + offsets.push(start); + (start + inner.as_slice().len(), offsets) + }, + ); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + for inner in self.0.iter() { + writer.write_all(inner.as_slice())?; + } + } + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + DynVecType::new_unchecked(inner.into()) + } +} +pub struct DynVecTypeIterator(DynVecType, usize, usize); +impl ::core::iter::Iterator for DynVecTypeIterator { + type Item = FixVecType; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl ::core::iter::ExactSizeIterator for DynVecTypeIterator { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::IntoIterator for DynVecType { + type Item = FixVecType; + type IntoIter = DynVecTypeIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + DynVecTypeIterator(self, 0, len) + } +} +impl<'r> DynVecTypeReader<'r> { + pub fn iter<'t>(&'t self) -> DynVecTypeReaderIterator<'t, 'r> { + DynVecTypeReaderIterator(&self, 0, self.len()) + } +} +pub struct DynVecTypeReaderIterator<'t, 'r>(&'t DynVecTypeReader<'r>, usize, usize); +impl<'t: 'r, 'r> ::core::iter::Iterator for DynVecTypeReaderIterator<'t, 'r> { + type Item = FixVecTypeReader<'t>; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl<'t: 'r, 'r> ::core::iter::ExactSizeIterator for DynVecTypeReaderIterator<'t, 'r> { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::FromIterator for DynVecType { + fn from_iter>(iter: T) -> Self { + Self::new_builder().extend(iter).build() + } +} +#[derive(Clone)] +pub struct OptType(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for OptType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for OptType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for OptType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + if let Some(v) = self.to_opt() { + write!(f, "{}(Some({}))", Self::NAME, v) + } else { + write!(f, "{}(None)", Self::NAME) + } + } +} +impl ::core::default::Default for OptType { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + OptType::new_unchecked(v) + } +} +impl OptType { + const DEFAULT_VALUE: [u8; 0] = []; + pub fn is_none(&self) -> bool { + self.0.is_empty() + } + pub fn is_some(&self) -> bool { + !self.0.is_empty() + } + pub fn to_opt(&self) -> Option { + if self.is_none() { + None + } else { + Some(DynVecType::new_unchecked(self.0.clone())) + } + } + pub fn as_reader<'r>(&'r self) -> OptTypeReader<'r> { + OptTypeReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for OptType { + type Builder = OptTypeBuilder; + const NAME: &'static str = "OptType"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + OptType(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + OptTypeReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + OptTypeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().set(self.to_opt()) + } +} +#[derive(Clone, Copy)] +pub struct OptTypeReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for OptTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for OptTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for OptTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + if let Some(v) = self.to_opt() { + write!(f, "{}(Some({}))", Self::NAME, v) + } else { + write!(f, "{}(None)", Self::NAME) + } + } +} +impl<'r> OptTypeReader<'r> { + pub fn is_none(&self) -> bool { + self.0.is_empty() + } + pub fn is_some(&self) -> bool { + !self.0.is_empty() + } + pub fn to_opt(&self) -> Option> { + if self.is_none() { + None + } else { + Some(DynVecTypeReader::new_unchecked(self.as_slice())) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for OptTypeReader<'r> { + type Entity = OptType; + const NAME: &'static str = "OptTypeReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + OptTypeReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + if !slice.is_empty() { + DynVecTypeReader::verify(&slice[..], compatible)?; + } + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct OptTypeBuilder(pub(crate) Option); +impl OptTypeBuilder { + pub fn set(mut self, v: Option) -> Self { + self.0 = v; + self + } +} +impl molecule::prelude::Builder for OptTypeBuilder { + type Entity = OptType; + const NAME: &'static str = "OptTypeBuilder"; + fn expected_length(&self) -> usize { + self.0 + .as_ref() + .map(|ref inner| inner.as_slice().len()) + .unwrap_or(0) + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + self.0 + .as_ref() + .map(|ref inner| writer.write_all(inner.as_slice())) + .unwrap_or(Ok(())) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + OptType::new_unchecked(inner.into()) + } +} +impl From for OptType { + fn from(value: DynVecType) -> Self { + Self::new_builder().set(Some(value)).build() + } +} +#[derive(Clone)] +pub struct TableType(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for TableType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for TableType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for TableType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "f1", self.f1())?; + write!(f, ", {}: {}", "f2", self.f2())?; + write!(f, ", {}: {}", "f3", self.f3())?; + write!(f, ", {}: {}", "f4", self.f4())?; + write!(f, ", {}: {}", "f5", self.f5())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for TableType { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + TableType::new_unchecked(v) + } +} +impl TableType { + const DEFAULT_VALUE: [u8; 39] = [ + 39, 0, 0, 0, 24, 0, 0, 0, 28, 0, 0, 0, 32, 0, 0, 0, 36, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 5; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn f1(&self) -> FixVecType { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + FixVecType::new_unchecked(self.0.slice(start..end)) + } + pub fn f2(&self) -> DynVecType { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + DynVecType::new_unchecked(self.0.slice(start..end)) + } + pub fn f3(&self) -> StructType { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + StructType::new_unchecked(self.0.slice(start..end)) + } + pub fn f4(&self) -> ArrayType { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + ArrayType::new_unchecked(self.0.slice(start..end)) + } + pub fn f5(&self) -> OptType { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[24..]) as usize; + OptType::new_unchecked(self.0.slice(start..end)) + } else { + OptType::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> TableTypeReader<'r> { + TableTypeReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for TableType { + type Builder = TableTypeBuilder; + const NAME: &'static str = "TableType"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + TableType(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + TableTypeReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + TableTypeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .f1(self.f1()) + .f2(self.f2()) + .f3(self.f3()) + .f4(self.f4()) + .f5(self.f5()) + } +} +#[derive(Clone, Copy)] +pub struct TableTypeReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for TableTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for TableTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for TableTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "f1", self.f1())?; + write!(f, ", {}: {}", "f2", self.f2())?; + write!(f, ", {}: {}", "f3", self.f3())?; + write!(f, ", {}: {}", "f4", self.f4())?; + write!(f, ", {}: {}", "f5", self.f5())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> TableTypeReader<'r> { + pub const FIELD_COUNT: usize = 5; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn f1(&self) -> FixVecTypeReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + FixVecTypeReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn f2(&self) -> DynVecTypeReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + DynVecTypeReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn f3(&self) -> StructTypeReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + StructTypeReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn f4(&self) -> ArrayTypeReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + ArrayTypeReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn f5(&self) -> OptTypeReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[24..]) as usize; + OptTypeReader::new_unchecked(&self.as_slice()[start..end]) + } else { + OptTypeReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for TableTypeReader<'r> { + type Entity = TableType; + const NAME: &'static str = "TableTypeReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + TableTypeReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + FixVecTypeReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + DynVecTypeReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + StructTypeReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + ArrayTypeReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + OptTypeReader::verify(&slice[offsets[4]..offsets[5]], compatible)?; + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct TableTypeBuilder { + pub(crate) f1: FixVecType, + pub(crate) f2: DynVecType, + pub(crate) f3: StructType, + pub(crate) f4: ArrayType, + pub(crate) f5: OptType, +} +impl TableTypeBuilder { + pub const FIELD_COUNT: usize = 5; + pub fn f1(mut self, v: FixVecType) -> Self { + self.f1 = v; + self + } + pub fn f2(mut self, v: DynVecType) -> Self { + self.f2 = v; + self + } + pub fn f3(mut self, v: StructType) -> Self { + self.f3 = v; + self + } + pub fn f4(mut self, v: ArrayType) -> Self { + self.f4 = v; + self + } + pub fn f5(mut self, v: OptType) -> Self { + self.f5 = v; + self + } +} +impl molecule::prelude::Builder for TableTypeBuilder { + type Entity = TableType; + const NAME: &'static str = "TableTypeBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.f1.as_slice().len() + + self.f2.as_slice().len() + + self.f3.as_slice().len() + + self.f4.as_slice().len() + + self.f5.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.f1.as_slice().len(); + offsets.push(total_size); + total_size += self.f2.as_slice().len(); + offsets.push(total_size); + total_size += self.f3.as_slice().len(); + offsets.push(total_size); + total_size += self.f4.as_slice().len(); + offsets.push(total_size); + total_size += self.f5.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.f1.as_slice())?; + writer.write_all(self.f2.as_slice())?; + writer.write_all(self.f3.as_slice())?; + writer.write_all(self.f4.as_slice())?; + writer.write_all(self.f5.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + TableType::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct UnionType(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for UnionType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for UnionType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for UnionType { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") + } +} +impl ::core::default::Default for UnionType { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + UnionType::new_unchecked(v) + } +} +impl UnionType { + const DEFAULT_VALUE: [u8; 7] = [0, 0, 0, 0, 0, 0, 0]; + pub const ITEMS_COUNT: usize = 5; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) + } + pub fn to_enum(&self) -> UnionTypeUnion { + let inner = self.0.slice(molecule::NUMBER_SIZE..); + match self.item_id() { + 0 => ArrayType::new_unchecked(inner).into(), + 1 => StructType::new_unchecked(inner).into(), + 2 => FixVecType::new_unchecked(inner).into(), + 3 => DynVecType::new_unchecked(inner).into(), + 4 => TableType::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), + } + } + pub fn as_reader<'r>(&'r self) -> UnionTypeReader<'r> { + UnionTypeReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for UnionType { + type Builder = UnionTypeBuilder; + const NAME: &'static str = "UnionType"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + UnionType(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + UnionTypeReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + UnionTypeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().set(self.to_enum()) + } +} +#[derive(Clone, Copy)] +pub struct UnionTypeReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for UnionTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for UnionTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for UnionTypeReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") + } +} +impl<'r> UnionTypeReader<'r> { + pub const ITEMS_COUNT: usize = 5; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) + } + pub fn to_enum(&self) -> UnionTypeUnionReader<'r> { + let inner = &self.as_slice()[molecule::NUMBER_SIZE..]; + match self.item_id() { + 0 => ArrayTypeReader::new_unchecked(inner).into(), + 1 => StructTypeReader::new_unchecked(inner).into(), + 2 => FixVecTypeReader::new_unchecked(inner).into(), + 3 => DynVecTypeReader::new_unchecked(inner).into(), + 4 => TableTypeReader::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), + } + } +} +impl<'r> molecule::prelude::Reader<'r> for UnionTypeReader<'r> { + type Entity = UnionType; + const NAME: &'static str = "UnionTypeReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + UnionTypeReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let item_id = molecule::unpack_number(slice); + let inner_slice = &slice[molecule::NUMBER_SIZE..]; + match item_id { + 0 => ArrayTypeReader::verify(inner_slice, compatible), + 1 => StructTypeReader::verify(inner_slice, compatible), + 2 => FixVecTypeReader::verify(inner_slice, compatible), + 3 => DynVecTypeReader::verify(inner_slice, compatible), + 4 => TableTypeReader::verify(inner_slice, compatible), + _ => ve!(Self, UnknownItem, Self::ITEMS_COUNT, item_id), + }?; + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct UnionTypeBuilder(pub(crate) UnionTypeUnion); +impl UnionTypeBuilder { + pub const ITEMS_COUNT: usize = 5; + pub fn set(mut self, v: I) -> Self + where + I: ::core::convert::Into, + { + self.0 = v.into(); + self + } +} +impl molecule::prelude::Builder for UnionTypeBuilder { + type Entity = UnionType; + const NAME: &'static str = "UnionTypeBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE + self.0.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(&molecule::pack_number(self.0.item_id()))?; + writer.write_all(self.0.as_slice()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + UnionType::new_unchecked(inner.into()) + } +} +#[derive(Debug, Clone)] +pub enum UnionTypeUnion { + ArrayType(ArrayType), + StructType(StructType), + FixVecType(FixVecType), + DynVecType(DynVecType), + TableType(TableType), +} +#[derive(Debug, Clone, Copy)] +pub enum UnionTypeUnionReader<'r> { + ArrayType(ArrayTypeReader<'r>), + StructType(StructTypeReader<'r>), + FixVecType(FixVecTypeReader<'r>), + DynVecType(DynVecTypeReader<'r>), + TableType(TableTypeReader<'r>), +} +impl ::core::default::Default for UnionTypeUnion { + fn default() -> Self { + UnionTypeUnion::ArrayType(::core::default::Default::default()) + } +} +impl ::core::fmt::Display for UnionTypeUnion { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + UnionTypeUnion::ArrayType(ref item) => { + write!(f, "{}::{}({})", Self::NAME, ArrayType::NAME, item) + } + UnionTypeUnion::StructType(ref item) => { + write!(f, "{}::{}({})", Self::NAME, StructType::NAME, item) + } + UnionTypeUnion::FixVecType(ref item) => { + write!(f, "{}::{}({})", Self::NAME, FixVecType::NAME, item) + } + UnionTypeUnion::DynVecType(ref item) => { + write!(f, "{}::{}({})", Self::NAME, DynVecType::NAME, item) + } + UnionTypeUnion::TableType(ref item) => { + write!(f, "{}::{}({})", Self::NAME, TableType::NAME, item) + } + } + } +} +impl<'r> ::core::fmt::Display for UnionTypeUnionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + UnionTypeUnionReader::ArrayType(ref item) => { + write!(f, "{}::{}({})", Self::NAME, ArrayType::NAME, item) + } + UnionTypeUnionReader::StructType(ref item) => { + write!(f, "{}::{}({})", Self::NAME, StructType::NAME, item) + } + UnionTypeUnionReader::FixVecType(ref item) => { + write!(f, "{}::{}({})", Self::NAME, FixVecType::NAME, item) + } + UnionTypeUnionReader::DynVecType(ref item) => { + write!(f, "{}::{}({})", Self::NAME, DynVecType::NAME, item) + } + UnionTypeUnionReader::TableType(ref item) => { + write!(f, "{}::{}({})", Self::NAME, TableType::NAME, item) + } + } + } +} +impl UnionTypeUnion { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + UnionTypeUnion::ArrayType(ref item) => write!(f, "{}", item), + UnionTypeUnion::StructType(ref item) => write!(f, "{}", item), + UnionTypeUnion::FixVecType(ref item) => write!(f, "{}", item), + UnionTypeUnion::DynVecType(ref item) => write!(f, "{}", item), + UnionTypeUnion::TableType(ref item) => write!(f, "{}", item), + } + } +} +impl<'r> UnionTypeUnionReader<'r> { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + UnionTypeUnionReader::ArrayType(ref item) => write!(f, "{}", item), + UnionTypeUnionReader::StructType(ref item) => write!(f, "{}", item), + UnionTypeUnionReader::FixVecType(ref item) => write!(f, "{}", item), + UnionTypeUnionReader::DynVecType(ref item) => write!(f, "{}", item), + UnionTypeUnionReader::TableType(ref item) => write!(f, "{}", item), + } + } +} +impl ::core::convert::From for UnionTypeUnion { + fn from(item: ArrayType) -> Self { + UnionTypeUnion::ArrayType(item) + } +} +impl ::core::convert::From for UnionTypeUnion { + fn from(item: StructType) -> Self { + UnionTypeUnion::StructType(item) + } +} +impl ::core::convert::From for UnionTypeUnion { + fn from(item: FixVecType) -> Self { + UnionTypeUnion::FixVecType(item) + } +} +impl ::core::convert::From for UnionTypeUnion { + fn from(item: DynVecType) -> Self { + UnionTypeUnion::DynVecType(item) + } +} +impl ::core::convert::From for UnionTypeUnion { + fn from(item: TableType) -> Self { + UnionTypeUnion::TableType(item) + } +} +impl<'r> ::core::convert::From> for UnionTypeUnionReader<'r> { + fn from(item: ArrayTypeReader<'r>) -> Self { + UnionTypeUnionReader::ArrayType(item) + } +} +impl<'r> ::core::convert::From> for UnionTypeUnionReader<'r> { + fn from(item: StructTypeReader<'r>) -> Self { + UnionTypeUnionReader::StructType(item) + } +} +impl<'r> ::core::convert::From> for UnionTypeUnionReader<'r> { + fn from(item: FixVecTypeReader<'r>) -> Self { + UnionTypeUnionReader::FixVecType(item) + } +} +impl<'r> ::core::convert::From> for UnionTypeUnionReader<'r> { + fn from(item: DynVecTypeReader<'r>) -> Self { + UnionTypeUnionReader::DynVecType(item) + } +} +impl<'r> ::core::convert::From> for UnionTypeUnionReader<'r> { + fn from(item: TableTypeReader<'r>) -> Self { + UnionTypeUnionReader::TableType(item) + } +} +impl UnionTypeUnion { + pub const NAME: &'static str = "UnionTypeUnion"; + pub fn as_bytes(&self) -> molecule::bytes::Bytes { + match self { + UnionTypeUnion::ArrayType(item) => item.as_bytes(), + UnionTypeUnion::StructType(item) => item.as_bytes(), + UnionTypeUnion::FixVecType(item) => item.as_bytes(), + UnionTypeUnion::DynVecType(item) => item.as_bytes(), + UnionTypeUnion::TableType(item) => item.as_bytes(), + } + } + pub fn as_slice(&self) -> &[u8] { + match self { + UnionTypeUnion::ArrayType(item) => item.as_slice(), + UnionTypeUnion::StructType(item) => item.as_slice(), + UnionTypeUnion::FixVecType(item) => item.as_slice(), + UnionTypeUnion::DynVecType(item) => item.as_slice(), + UnionTypeUnion::TableType(item) => item.as_slice(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + UnionTypeUnion::ArrayType(_) => 0, + UnionTypeUnion::StructType(_) => 1, + UnionTypeUnion::FixVecType(_) => 2, + UnionTypeUnion::DynVecType(_) => 3, + UnionTypeUnion::TableType(_) => 4, + } + } + pub fn item_name(&self) -> &str { + match self { + UnionTypeUnion::ArrayType(_) => "ArrayType", + UnionTypeUnion::StructType(_) => "StructType", + UnionTypeUnion::FixVecType(_) => "FixVecType", + UnionTypeUnion::DynVecType(_) => "DynVecType", + UnionTypeUnion::TableType(_) => "TableType", + } + } + pub fn as_reader<'r>(&'r self) -> UnionTypeUnionReader<'r> { + match self { + UnionTypeUnion::ArrayType(item) => item.as_reader().into(), + UnionTypeUnion::StructType(item) => item.as_reader().into(), + UnionTypeUnion::FixVecType(item) => item.as_reader().into(), + UnionTypeUnion::DynVecType(item) => item.as_reader().into(), + UnionTypeUnion::TableType(item) => item.as_reader().into(), + } + } +} +impl<'r> UnionTypeUnionReader<'r> { + pub const NAME: &'r str = "UnionTypeUnionReader"; + pub fn as_slice(&self) -> &'r [u8] { + match self { + UnionTypeUnionReader::ArrayType(item) => item.as_slice(), + UnionTypeUnionReader::StructType(item) => item.as_slice(), + UnionTypeUnionReader::FixVecType(item) => item.as_slice(), + UnionTypeUnionReader::DynVecType(item) => item.as_slice(), + UnionTypeUnionReader::TableType(item) => item.as_slice(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + UnionTypeUnionReader::ArrayType(_) => 0, + UnionTypeUnionReader::StructType(_) => 1, + UnionTypeUnionReader::FixVecType(_) => 2, + UnionTypeUnionReader::DynVecType(_) => 3, + UnionTypeUnionReader::TableType(_) => 4, + } + } + pub fn item_name(&self) -> &str { + match self { + UnionTypeUnionReader::ArrayType(_) => "ArrayType", + UnionTypeUnionReader::StructType(_) => "StructType", + UnionTypeUnionReader::FixVecType(_) => "FixVecType", + UnionTypeUnionReader::DynVecType(_) => "DynVecType", + UnionTypeUnionReader::TableType(_) => "TableType", + } + } +} +impl From for UnionType { + fn from(value: ArrayType) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for UnionType { + fn from(value: StructType) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for UnionType { + fn from(value: FixVecType) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for UnionType { + fn from(value: DynVecType) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for UnionType { + fn from(value: TableType) -> Self { + Self::new_builder().set(value).build() + } +} diff --git a/fuzzing/rust/src/lib.rs b/fuzzing/rust/src/lib.rs new file mode 100644 index 0000000..069dee6 --- /dev/null +++ b/fuzzing/rust/src/lib.rs @@ -0,0 +1,2 @@ +pub mod definitions; +pub use molecule; diff --git a/tools/codegen/src/generator/languages/c/reader.rs b/tools/codegen/src/generator/languages/c/reader.rs index 26ec6ff..59b24b4 100644 --- a/tools/codegen/src/generator/languages/c/reader.rs +++ b/tools/codegen/src/generator/languages/c/reader.rs @@ -235,6 +235,9 @@ impl GenReader for ast::DynVec { w!(o, " mol_seg_t inner; "); w!(o, " inner.ptr = input->ptr + offset; "); w!(o, " inner.size = end - offset; "); + w!(o, " if (mol_contained_by(&inner, input)!=MOL_OK) {{"); + w!(o, " return MOL_ERR_OFFSET; "); + w!(o, " }} "); w!(o, " mol_errno errno = {}(&inner, compatible); ", f); w!(o, " if (errno != MOL_OK) {{ "); w!(o, " return MOL_ERR_DATA; "); @@ -247,6 +250,9 @@ impl GenReader for ast::DynVec { w!(o, " mol_seg_t inner; "); w!(o, " inner.ptr = input->ptr + offset; "); w!(o, " inner.size = total_size - offset; "); + w!(o, " if (mol_contained_by(&inner, input) != MOL_OK) {{ "); + w!(o, " return MOL_ERR_OFFSET; "); + w!(o, " }} "); w!(o, " return {}(&inner, compatible); ", f); w!(o, "}} "); Ok(()) @@ -350,6 +356,9 @@ impl GenReader for ast::Table { let f = format!("{}_verify", field.typ().reader_prefix()); w!(o, " inner.ptr = input->ptr + offsets[{}]; ", i); w!(o, " inner.size = offsets[{}] - offsets[{}]; ", j, i); + w!(o, " if (mol_contained_by(&inner, input)!=MOL_OK) {{"); + w!(o, " return MOL_ERR_OFFSET; "); + w!(o, " }} "); w!(o, " errno = {}(&inner, compatible); ", f); w!(o, " if (errno != MOL_OK) {{ "); w!(o, " return MOL_ERR_DATA; ");